本文共 4143 字,大约阅读时间需要 13 分钟。
前面一篇介绍了两个线程之间的通信,那么三个线程和三个以上线程之间的通信是如何实现呢。我们前面一篇在查询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方法在同步函数或者同步代码块中,释放锁。转载地址:http://nzows.baihongyu.com/