本文章内容整理自:张孝祥_Java多线程与并发库高级应用视频教程。
有些时候,线程间需要传递消息,比如下面这道面试题:
子线程循环10次,然后主线程循环100次,然后又回到子线程循环50次,然后再回到主线程循环100次。以上过程一共循环50次。
通过分析可以知道,主线程和子线程是互斥的,即主线程和子线程不能同时执行。此外,主线程和子线程有固定的轮换关系,主线程执行完后,必须是子线程接着执行,然后又是主线程执行。
要达到这种效果,需要两个线程间可以通信。子线程执行完了,就通知主线程执行。主线程执行完了,再通知子线程执行。如此往复。
下面直接贴出代码
package com.sky.thread; public class Test4 { private boolean mainOrSub = true;//线程间通信的变量 public static void main(String[] args) { final Test4 t4 = new Test4(); new Thread(new Runnable() { @Override public void run() { //执行50次主线程 for (int i = 0; i < 50; i++) { try { t4.mainThread(); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { //执行50次子线程 for (int i = 0; i < 50; i++) { try { t4.subThread(); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } //主线程执行的方法 public synchronized void mainThread() throws InterruptedException { //判断是否轮到自己执行 //此处用while代替if,可以提高程序的健壮性。 //线程有时会自己醒来,如果用if,当线程自己醒来后会接着执行this.wait()后面的代码,这样是不对的。 //而使用while,线程自己醒来后,根据while的规则,会再判断一次mainOrSub的值。 if (mainOrSub) { //如果mainOrSub是true,表示不该自己执行。于是把线程挂起。 this.wait(); } for (int i = 0; i < 100; i++) { System.out.println("main-"+Thread.currentThread().getName() + ":" + i); } //执行完毕后更改mainOrSub的状态,并唤醒其他线程 mainOrSub = true; this.notify(); } //子线程执行的方法 public synchronized void subThread() throws InterruptedException { //判断是否轮到自己执行 while (!mainOrSub) { //如果mainOrSub是false,表示不该自己执行。于是把线程挂起。 this.wait(); } for (int i = 0; i < 10; i++) { System.out.println("sub-"+Thread.currentThread().getName() + ":" + i); } //执行完毕后更改mainOrSub的状态,并唤醒其他线程 mainOrSub = false; this.notify(); } }
在上面的代码中,创建了一个变量mainOrSub用于线程间通信。通过mainOrSub的值来控制线程的交替执行。
可见,使用多个线程都可以访问到的变量,就可以实现线程间通信。
还有一点值得注意,在判断mainOrSub的值时,用while代替了if,这样可以提高程序的健壮性。因为使用wait()挂起的线程有时会自己醒来。如果用if,当线程自己醒来后会接着执行this.wait()后面的代码,而此时并不该它执行。如果用while,线程自己醒来后,根据while的规则,会再判断一次mainOrSub的值,这样就可以保证线程完全依照mainOrSub的值来决定要不要执行。
经验:要用到共同数据(包括同步锁)的若干个方法应该归在同一个类身上,这种设计体现了高内聚和程序的健壮性。