1.问题的引入
存在一个面试题:
编写代码实现子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次,然后再回到主线程又循环100次,如此循环50次。
2.问题分析
首先,明确问题中存在两个线程: 一个子线程 一个main线程,线程循环一次要中循环体的内容需要保证为一个整体(即需要对改内容同步,如上次说的打印姓名的例子一样,
打印张三的名字没有完成就不能打印李四的名字) 因此需要对操作进行同步 。
其次,子线程循环一次后是主线程循环,如此往复50次,那么两者之间就需要通信 告诉对象自己执行结束需要对象来执行
3.编码实现
package org.lkl.thread; /** * 线程同步通信 * @author Liaokailin * */ public class ThreadCommunication { public static void main(String[] args) { //子线程和主线程都是通过同一个对象b来调用其具体的方法 由于该方法加了synchronized关键字 那么两个能同步 final Business b = new Business() ; /** * 这里为子线程操作 */ new Thread(new Runnable() { @Override public void run() { for(int i = 1 ;i<=50 ;i++){ b.sub(i) ; } } }).start() ; for(int i = 1 ;i<=50 ;i++){ b.main(i) ; } } } /** * 子线程循环10次,接着主线程循环100次 * 对应的循环内容就是具体的业务操作 ,可以将其包装为一个类 */ class Business{ private boolean flag = true ; //标记位 /** * 子线程要实现的业务 需要同步 * @param i */ public synchronized void sub(int i){ while(!flag){ //这里也可以使用if关键字 但是由于if可能会出现线程的假唤醒操作 通过while循环可以避免该问题 try { wait() ; //不为真 表示当前属于main线程执行 ,此方法进入等待状态 } catch (InterruptedException e) { e.printStackTrace(); } } for(int j =1 ;j<=10;j++){ System.out.println("sub thread sequence of " + j +",loop of "+i); } flag = false ; notify() ; } /** * 主线程要实现的业务 需要同步 * @param i */ public synchronized void main(int i){ while(flag){ try { wait() ; //为真 表示应为为子线程执行 此方法进入等待状态 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } for(int j =1 ;j<=100;j++){ System.out.println("main thread sequence of " + j +",loop of "+i); } flag = true ; //修改标记位 让子线程来执行 但此时子线程可能在wait状态 需要进行唤醒操作 notify() ; } //备注: 线程的执行都是由cpu进行调度的 如果时间片到了子线程 但是子线程处于等待状态 那么cpu将调度其他线程来执行 }
4. 小结
通过wait 和notify 来实现线程之间的通信
要用到共同数据(包括同步锁) 的若干个方法或者共同算法应该归在同一个类上 !!!