发表于: 2018-03-11 10:51:11

1 670


今日完成

1.学习多线程之间的通信问题。

(1)需求有一个线程对一个对象进行赋值操作,另一个线程任务对对象进行取值操作。

用多线程写一个简单的demo。

public class WaitDemo2 {
public static void main(String[] args) {
Person a = new Person();
       TaskSet set = new TaskSet(a);
       TaskGet get = new TaskGet(a);
       
       
       Thread c = new Thread(set);
       Thread d = new Thread(get);
       c.start();
       d.start();
   }


}


class Person {
String name;
   String sex;
   Boolean flag = false;
}

class TaskSet implements Runnable {
private Person person;
   int x = 0;
   
   TaskSet(Person person) {
this.person = person;
   }

@Override
   public void run() {
while (true) {

if (person.flag) {

} else {

if (x == 0) {
person.name = "mike ";
                   person.sex = "男男男呐呐";
               } else {
try {
Thread.sleep(50);
                   } catch (InterruptedException e) {
e.printStackTrace();
                   }
person.name = "丽丽 ";
                   try {
Thread.sleep(50);
                   } catch (InterruptedException e) {
e.printStackTrace();
                   }
person.sex = "";
                   try {
Thread.sleep(50);
                   } catch (InterruptedException e) {
e.printStackTrace();
                   }
}
x = (x + 1) % 2;
           }
}
}
}

class TaskGet implements Runnable {
private Person person;
   
   
   TaskGet(Person person) {
this.person = person;
   }

@Override
   public void run() {
while (true) {
System.out.println(person.name + "....." + person.sex);
           person.flag = false;
           
       }

}
}

结果

分析原因

1.在赋值任务进行到一半的时候,cpu轮询到了取值的线程,然后取的值就变成了这样。

解决方案,将这两个线程进行同步。将赋值与取值的操作放在同步代码块里面,这里需要用同一个锁。这个使用person对象

synchronized (person){
if (person.flag) {

} else {

if (x == 0) {
person.name = "mike ";
           person.sex = "男男男呐呐";
       } else {
try {
Thread.sleep(50);
           } catch (InterruptedException e) {
e.printStackTrace();
           }
person.name = "丽丽 ";
           try {
Thread.sleep(50);
           } catch (InterruptedException e) {
e.printStackTrace();
           }
person.sex = "";
           try {
Thread.sleep(50);
           } catch (InterruptedException e) {
e.printStackTrace();
           }
}
x = (x + 1) % 2;
   }
}
synchronized(person){
System.out.println(person.name + "....." + person.sex);
   person.flag = false;
}

虽然结果正确了,但是还是不是我们想要的,这里想要完成,赋值一次,取值一尺的操作,就要用到线程之间的通信了。在a线程完成赋值后通知b线程可以取值了,在没有完成赋值之前让该线程处于等待状态。代码就是这样的了

public class WaitDemo2 {
public static void main(String[] args) {
Person a = new Person();
       TaskSet set = new TaskSet(a);
       TaskGet get = new TaskGet(a);
   
   
       Thread c = new Thread(set);
       Thread d = new Thread(get);
       c.start();
       d.start();
   }


}


class Person {
String name;
   String sex;
   Boolean flag = false;
}

class TaskSet implements Runnable {
private Person person;
   int x = 0;
   
   TaskSet(Person person) {
this.person = person;
   }

@Override
   public void run() {
while (true) {
synchronized(person){
if(person.flag){
try {
person.wait();
                   } catch (InterruptedException e) {
e.printStackTrace();
                   }
}else{

if (x == 0) {
person.name = "mike ";
                       person.sex = "男男男呐呐";
                   }else {
try {
Thread.sleep(50);
                       } catch (InterruptedException e) {
e.printStackTrace();
                       }
person.name = "丽丽 ";
                       try {
Thread.sleep(50);
                       } catch (InterruptedException e) {
e.printStackTrace();
                       }
person.sex = "";
                       try {
Thread.sleep(50);
                       } catch (InterruptedException e) {
e.printStackTrace();
                       }
}
x = (x+1)%2;
                   person.flag = true;
                   person.notify();
                   
               }



}
}


}
}

class TaskGet implements Runnable {
private Person person;

   
   TaskGet(Person person) {
this.person = person;
   }

@Override
   public void run() {
while (true) {
synchronized (person){
if(person.flag){
System.out.println(person.name+"....."+person.sex);
                   person.flag = false;
                   person.notify();
               }else{
try {
person.wait();
                   } catch (InterruptedException e) {
e.printStackTrace();
                   }
}

}

}

}
}

结果也是

①wait() 与 notify/notifyAll 方法必须在同步代码块中使用

wait() 与 notify/notifyAll() 是Object类的方法,在执行两个方法时,要先获得锁。那么怎么获得锁呢?

在这篇:JAVA多线程之Synchronized关键字--对象锁的特点文章中介绍了使用synchronized关键字获得锁。因此,wait() 与  notify/notifyAll() 经常与synchronized搭配使用,即在synchronized修饰的同步代码块或方法里面调用wait() 与  notify/notifyAll()方法。

 

②wait() 与  notify/notifyAll() 的执行过程

由于 wait() 与  notify/notifyAll() 是放在同步代码块中的,因此线程在执行它们时,肯定是进入了临界区中的,即该线程肯定是获得了锁的。

当线程执行wait()时,会把当前的锁释放,然后让出CPU,进入等待状态。

 当执行notify/notifyAll方法时,会唤醒一个处于等待该 对象锁 的线程,然后继续往下执行,直到执行完退出对象锁锁住的区域(synchronized修饰的代码块)后再释放锁。

从这里可以看出,notify/notifyAll()执行后,并不立即释放锁,而是要等到执行完临界区中代码后,再释放。故,在实际编程中,我们应该尽量在线程调用notify/notifyAll()后,立即退出临界区。即不要在notify/notifyAll()后面再写一些耗时的代码。

(2)死锁,一般出现在同步代码块嵌套中,出现的原因是线程之间都占用了对方的锁

public class DeadLockDemo {


public static void main(String[] args) {
Hero teemor = new Hero();
       Hero gaylun = new Hero();
       Thread a = new Thread() {
@Override
           public void run() {
synchronized (teemor) {
System.out.println("线程a已经占有了 teemor");
                   
//                    try {
//                        Thread.sleep(500);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
                   System.out.println("试图占有 gaylun");
                   synchronized(gaylun){
System.out.println("线程a已经占有了 gaylun");
                   }

}
}
};
       
       Thread b = new Thread(){
@Override
           public void run() {
synchronized (gaylun) {
System.out.println("线程a已经占有了 gaylun");
       
//                    try {
//                        Thread.sleep(500);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
                   System.out.println("试图占有 teemor");
                   synchronized(teemor){
System.out.println("线程a占有 teemor");
                   }

}
}
};
       
       a.start();
       b.start();
   }

}

class Hero {

}

明日计划

1.方案评审

遇到问题

1.动态定时任务

收获

1.多线程的中通信问题的学习。


返回列表 返回列表
评论

    分享到