版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011541946/article/details/85869191
前面一篇介绍了两个线程之间的通信,那么三个线程和三个以上线程之间的通信是如何实现呢。我们前面一篇在查询Object类的时候,知道有一个wait()和notify()方法,同时还有一个notifyAll()方法。这个notfiyAll()方法就是来解决三个以上线程通信的。
1.基于前面知识,添加一个线程,看看执行效果
package thread;
public class NotifyAll_Demo {
public static void main(String[] args) {
Printer2 p = new Printer2();
new Thread() {
public void run() {
while(true) {
try {
p.print1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread() {
public void run() {
while(true) {
try {
p.print2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread() {
public void run() {
while(true) {
try {
p.print3();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
}
class Printer2 {
private int flag = 1;
public void print1() throws InterruptedException {
synchronized (this) {
if(flag != 1) {
this.wait(); // 设置线程等待,如果flag 不等于1
}
System.out.print("跟");
System.out.print("我");
System.out.print("一");
System.out.print("起");
System.out.println("念");
flag = 2;
this.notify(); // 设置flag等于2,使用线程唤醒功能,其他线程就可以启动
}
}
public void print2() throws InterruptedException {
synchronized (this) {
if(flag != 2) {
this.wait(); // 设置线程等待,如果flag 不等于2
}
System.out.print("做");
System.out.print("测");
System.out.print("试");
System.out.print("死");
System.out.print("路");
System.out.print("一");
System.out.println("条");
flag = 3;
this.notify(); //随机唤醒单个等待的线程
}
}
public void print3() throws InterruptedException {
synchronized (this) {
if(flag != 3) {
this.wait(); // 设置线程等待,如果flag 不等于2
}
System.out.print("信");
System.out.print("才");
System.out.print("怪");
System.out.println("呢");
flag = 1;
this.notify(); //随机唤醒单个等待的线程
}
}
}
运行效果:
做测试死路一条
跟我一起念
信才怪呢
做测试死路一条
跟我一起念
信才怪呢
做测试死路一条
跟我一起念
信才怪呢
做测试死路一条
跟我一起念
信才怪呢
做测试死路一条
跟我一起念
发现打印顺序有问题,主要有两个原因,if语句有一个特点,代码在哪里停止(上面wait)就在哪里起来。第二个特点就是notify()是随机唤醒等待线程。这个随机特点就造成了打印结果顺序不可控。
2.if语句换成while语句,notify()方法换成notifyAll()方法
if没有每次都对flag进行判断,但是while语句会每次都进行条件判断。notifyAll()就是把全部的线程都唤醒,然后这些线程去判断,再执行相关打印。
package thread;
public class NotifyAll_Demo {
public static void main(String[] args) {
Printer2 p = new Printer2();
new Thread() {
public void run() {
while(true) {
try {
p.print1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread() {
public void run() {
while(true) {
try {
p.print2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread() {
public void run() {
while(true) {
try {
p.print3();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
}
class Printer2 {
private int flag = 1;
public void print1() throws InterruptedException {
synchronized (this) {
while(flag != 1) {
this.wait(); // 设置线程等待,如果flag 不等于1
}
System.out.print("跟");
System.out.print("我");
System.out.print("一");
System.out.print("起");
System.out.println("念");
flag = 2;
this.notifyAll();
}
}
public void print2() throws InterruptedException {
synchronized (this) {
while(flag != 2) {
this.wait(); // 设置线程等待,如果flag 不等于2
}
System.out.print("做");
System.out.print("测");
System.out.print("试");
System.out.print("死");
System.out.print("路");
System.out.print("一");
System.out.println("条");
flag = 3;
this.notifyAll();
}
}
public void print3() throws InterruptedException {
synchronized (this) {
while(flag != 3) {
this.wait(); // 设置线程等待,如果flag 不等于2
}
System.out.print("信");
System.out.print("才");
System.out.print("怪");
System.out.println("呢");
flag = 1;
this.notifyAll();
}
}
}
运行效果:
跟我一起念
做测试死路一条
信才怪呢
跟我一起念
做测试死路一条
信才怪呢
跟我一起念
做测试死路一条
信才怪呢
跟我一起念
做测试死路一条
信才怪呢
跟我一起念
做测试死路一条
信才怪呢
...
多线程之间需要注意的问题
1.在同步代码块中,用哪个对象锁,就用哪个对象调用wait方法(例如上面的this)
2.为什么wait方法和notify方法定义在Object这个类中
因为锁对象可以是任意对象,Object是所有类的基类,所以wait方法和notify方法需要定义在Object类中
3.sleep方法和wait方法的区别
第一个区别:sleep方法必须传入参数,参数就是时间,时间到了自动醒来。wait方法可以传入参数也可以不传入参数,传入参数就是在参数时间结束后等待,不传入参数就是直接等待。
第二个区别:sleep方法在同步函数或者同步代码块中,不释放锁。wait方法在同步函数或者同步代码块中,释放锁。