发表于: 2018-03-11 10:51:11
1 672
今日完成
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.多线程的中通信问题的学习。
评论