java thread study
0. 用runnable创建线程具有面向对象的思想。
1. quartz 定时器开源库。
3. 多线程间的互斥:
(1)多线程间的互斥,用synchronized关键字,两个线程用互斥锁必须用同一个对象才能实现互斥。
(2) 两个非静态函数前加synchronized关键字,它们的公用锁是this,就是当前对象实例。
(3)静态函数前加synchronized关键字,它用的锁对象是.class字节码,这个时u候与要将非静态函数的synchronized(this)锁改为synchronized(MyClass.class),即字节码锁
两个函数这才使用了同一个锁:类的字节码对象,从而才实现了互斥。
例如:2 个线程调用同一个Output对象的output1(“gaoxiaowei”)和output2(“lichao”)两个函数, 会出现打印gaoxiaowei lichao gaolichao xiaowei这样第二行错乱的问题。
在这里临界资源是输出屏幕? 我如果让一个线程调用ouput1对象的output,然后另一个线程调用output2对象的output,在不加锁的情况下会错乱吗?
答:
(1)如果output函数的同步锁是object.class字节码时,就不会错乱,因为两个线程 的两个output对象在执行output1函数时,用的是同一把锁object.class;
(2)如果output的同步锁是this,那么会错乱,因为两个线程分别持有2个对象output1与ouput2,是两个this,因此output函数上的synchronized用的o是2把不同的
this锁,各自执行各自的,都可以在这个临界资源——屏幕上输出。如第一个线程正在输出gaolichao结果第二个线程打印lichao插到了第一个线程的输出中间。
(3)是的,这里的临界资源就是显示器,而不是公用的output类对象,因为即使2个线程分别创建一个output对象:output1与output2,如果锁不是同一个的话,
也会出现打印错误。除非有2个显示器,一个线程往显示器1输出,另一个线程往显示器2输出,这才不冲突,因为2个已经是1对1,不存在公用竞争问题。
4.多线程间的同步
wait 和 notify
现在有这么一个题目:子线程执行10次,然后主线程再执行100次,接着轮到子线程再执行10次,然后主线程又执行100次,两个线程这样轮流执行,总共50回。
step1: 定义一个业务类,封装两个函数:(1)打印10次sub (2)打印100次main;
step2: 定义1个子线程,外层for循环都是50次,然后每循环1次调用业务类中的 函数(1u)打印10次sub
主线程,外层for循环都是50次,然后每循环1次调用业务类中的 函数(2)打印50次main
step3:先解决互斥问题:就是在打印sub的10次循环时,不能穿插打印main;同理打印main的100次的时候,不能穿插子线程的sub打印。这个好办,给业务类的
函数1和函数2前加synchronized关键字,这样就实现了打印sub的10次时,由于正在占用同一个对象锁this,因此它不会被函数(2)打断。
step4:解决同步配合问题,先子线程打印10次,子线程打印完了,然后执行notify,唤醒主线程去打印100次(主线程刚开始会调用waite),然后主线程打印完100次,再去唤醒子线程去打印。
注意synchronized括起来的对象要与调用wait,notify是同一个对象,并且这个object.notify,object.wait中的object要被括在synchronized里,否则会报错:java.lang.IllegalMonitorStateException
实例代码如下:
import java.util.concurrent.atomic.AtomicInteger;
public class TraditionalThreadCommunication {
/**
* @param args
*/
public static void main(String[] args) {
final Business business = new Business();
new Thread(
new Runnable() {
@Override
public void run() {
for(int i=1;i<=50;i++){
business.sub(i);
}
}
}
).start();
for(int i=1;i<=50;i++){
business.main(i);
}
}
}
class Business {
private boolean bShouldSub = true;
Object obj;
public Business()
{
obj = new Object();
}
public synchronized void sub(int i){
synchronized(obj)
{
while(!bShouldSub){
try {
obj.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for(int j=1;j<=10;j++){
System.out.println("sub thread sequence of " + j + ",loop of " + i);
}
bShouldSub = false;
obj.notify();
}
}
public void main(int i){
synchronized(obj)
{
while(bShouldSub){
try {
obj.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for(int j=1;j<=100;j++){
System.out.println("main thread sequence of " + j + ",loop of " + i);
}
bShouldSub = true;
obj.notify();
}
}
}
或者:
public class TraditionalThreadCommunication {
public static void main(String[] args) {
final Business business = new Business();
new Thread(
new Runnable() {
@Override
public void run() {
for(int i=1;i<=50;i++){
business.sub(i);
}
}
}
).start();
for(int i=1;i<=50;i++){
business.main(i);
}
}
}
class Business {
private boolean bShouldSub = true;
public synchronized void sub(int i){
while(!bShouldSub){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for(int j=1;j<=10;j++){
System.out.println("sub thread sequence of " + j + ",loop of " + i);
}
bShouldSub = false;
this.notify();
}
public synchronized void main(int i){
while(bShouldSub){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for(int j=1;j<=100;j++){
System.out.println("main thread sequence of " + j + ",loop of " + i);
}
bShouldSub = true;
this.notify();
}
}
5. 多线程间的互斥,用synchronized关键字包裹的函数内部如果生成了 一个死循环线程,那么这个函数的锁子能释放吗?
答:能。因为synchronized是用于当前线程同步的;还有就是生成的那个线程并不会阻塞当前函数的执行,函数执行完成后自然会释放synchronized锁。
6.当一个线程处于sleep时,Thread.isAlive函数返回false
7.线程范围内的共享变量
同一个变量,在线程间共享,例如下面的变量x,线程内独立,表示线程内是一份独立的数据。
(1)可以用hashmap.put(Thread.name, data); 来实现
(2)ThreadLocal来实现
下面的x,是演示单个共享变量
package cn.itcast.heima2;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class ThreadLocalTest {
private static ThreadLocal<Integer> x = new ThreadLocal<Integer>();
private static ThreadLocal<MyThreadScopeData> myThreadScopeData = new ThreadLocal<MyThreadScopeData>();
public static void main(String[] args) {
for(int i=0;i<2;i++){
new Thread(new Runnable(){
@Override
public void run() {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName()
+ " has put data :" + data);
x.set(data);
/* MyThreadScopeData myData = new MyThreadScopeData();
myData.setName("name" + data);
myData.setAge(data);
myThreadScopeData.set(myData);*/
MyThreadScopeData.getThreadInstance().setName("name" + data);
MyThreadScopeData.getThreadInstance().setAge(data);
new A().get();
new B().get();
}
}).start();
}
}
static class A{
public void get(){
int data = x.get();
System.out.println("A from " + Thread.currentThread().getName()
+ " get data :" + data);
/* MyThreadScopeData myData = myThreadScopeData.get();;
System.out.println("A from " + Thread.currentThread().getName()
+ " getMyData: " + myData.getName() + "," +
myData.getAge());*/
MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
System.out.println("A from " + Thread.currentThread().getName()
+ " getMyData: " + myData.getName() + "," +
myData.getAge());
}
}
static class B{
public void get(){
int data = x.get();
System.out.println("B from " + Thread.currentThread().getName()
+ " get data :" + data);
MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
System.out.println("B from " + Thread.currentThread().getName()
+ " getMyData: " + myData.getName() + "," +
myData.getAge());
}
}
}
class MyThreadScopeData{
private MyThreadScopeData(){}
public static /*synchronized*/ MyThreadScopeData getThreadInstance(){
MyThreadScopeData instance = map.get();
if(instance == null){
instance = new MyThreadScopeData();
map.set(instance);
}
return instance;
}
//private static MyThreadScopeData instance = null;//new MyThreadScopeData();
private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
8.多个线程间共享数据的探讨
方法1:new Thread(new Runnable()
{
data1.decrement();
}
)
方法2: new Thread(new MyRunnable1(data2)).start();
new Thread(new MyRunnable2(data2)).start();
将数据data2作为构造函数参数传到Runnable里去。
方法3:
定义2个Runnable内部类,访问外部类的成员变量j
方法1和方法2的代码:
package cn.itcast.heima2;
public class MultiThreadShareData {
private static ShareData1 data1 = new ShareData1();
public static void main(String[] args) {
ShareData1 data2 = new ShareData1();
new Thread(new MyRunnable1(data2)).start();
new Thread(new MyRunnable2(data2)).start();
final ShareData1 data1 = new ShareData1();
new Thread(new Runnable(){
@Override
public void run() {
data1.decrement();
}
}).start();
new Thread(new Runnable(){
@Override
public void run() {
data1.increment();
}
}).start();
}
}
class MyRunnable1 implements Runnable{
private ShareData1 data1;
public MyRunnable1(ShareData1 data1){
this.data1 = data1;
}
public void run() {
data1.decrement();
}
}
class MyRunnable2 implements Runnable{
private ShareData1 data1;
public MyRunnable2(ShareData1 data1){
this.data1 = data1;
}
public void run() {
data1.increment();
}
}
class ShareData1 /*implements Runnable*/{
/* private int count = 100;
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
count--;
}
}*/
private int j = 0;
public synchronized void increment(){
j++;
}
public synchronized void decrement(){
j--;
}
}
方法3的代码:
外部类:
private int j = 0;
public synchronized void increment(){
j++;
}
public synchronized void decrement(){
j--;
}
内部类:
MyIncrementRunnable()
{
increment(); //内部类调用外部类成员,还是以外部类对象为同步锁
}
MyDecrementRunnable()
{
decrement();
}
文章来源: blog.csdn.net,作者:冉航--小虾米,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/gaoxiaoweiandy/article/details/100825669
- 点赞
- 收藏
- 关注作者
评论(0)