zoukankan      html  css  js  c++  java
  • java启动3个线程轮流打印数字

    转自:http://blog.csdn.net/u014011112/article/details/50988769

    http://blog.csdn.net/perrywork/article/details/16819153

    1. //一个关于线程的经典面试题,要求用三个线程,按顺序打印1,2,3,4,5.... 71,72,73,74, 75.  
    2. //线程1先打印1,2,3,4,5, 然后是线程2打印6,7,8,9,10, 然后是线程3打印11,12,13,14,15.   
    3. //接着再由线程1打印16,17,18,19,20....以此类推, 直到线程3打印到75。  
    4.   
    5. public class Printer implements Runnable {  
    6.   
    7.     int id;  
    8.     static int num = 1;  
    9.   
    10.     public Printer(int id) {  
    11.         this.id = id;  
    12.     }  
    13.   
    14.     @Override  
    15.     public void run() {  
    16.         synchronized (Printer.class) {  
    17.             while (num <= 75) {  
    18.                 if (num / 5 % 3 == id) {  
    19.                     System.out.print("id" + id + ":");  
    20.                     for (int i = 0; i < 5; i++)  
    21.                         System.out.print(num++ + ",");  
    22.                     System.out.println();  
    23.                     Printer.class.notifyAll();  
    24.                 } else {  
    25.                     try {  
    26.                         Printer.class.wait();  
    27.                     } catch (InterruptedException e) {  
    28.                         e.printStackTrace();  
    29.                     }  
    30.                 }  
    31.             }  
    32.         }  
    33.     }  
    34.   
    35.     public static void main(String[] args) {  
    36.   
    37.         new Thread(new Printer(0)).start();  
    38.         new Thread(new Printer(1)).start();  
    39.         new Thread(new Printer(2)).start();  
    40.     }  
    41. }  

    打印结果:

    [java] view plain copy
     
    1. id0:1,2,3,4,5,  
    2. id1:6,7,8,9,10,  
    3. id2:11,12,13,14,15,  
    4. id0:16,17,18,19,20,  
    5. id1:21,22,23,24,25,  
    6. id2:26,27,28,29,30,  
    7. id0:31,32,33,34,35,  
    8. id1:36,37,38,39,40,  
    9. id2:41,42,43,44,45,  
    10. id0:46,47,48,49,50,  
    11. id1:51,52,53,54,55,  
    12. id2:56,57,58,59,60,  
    13. id0:61,62,63,64,65,  
    14. id1:66,67,68,69,70,  
    15. id2:71,72,73,74,75,  

    /////////////////////////////////////////////////////////////////////////////

    原帖见:http://www.iteye.com/topic/1117703

    问题描述:

    一个关于线程的经典面试题,要求用三个线程,按顺序打印1,2,3,4,5.... 71,72,73,74, 75.

    线程1先打印1,2,3,4,5, 然后是线程2打印6,7,8,9,10, 然后是线程3打印11,12,13,14,15. 接着再由线程1打印16,17,18,19,20....以此类推, 直到线程3打印到75。

    直接上代码:

    Java代码  收藏代码
    1. package concurrent.test;  
    2.   
    3.   
    4. /** 
    5.  * 要求创建三个线程,输出1-75, 
    6.  * 最开始第一个线程输出1-5,第二个输出6-10,第三个输出11-15 
    7.  * 接着再第一个线程输出16-20...就这样循环下去,直到打印出75个数 
    8.  * @author qiaoxueshi 
    9.  * 
    10.  */  
    11. public class Print1to75 {  
    12.     static class Printer implements Runnable{  
    13.         static int num = 1; //开始数字  
    14.         static final int END = 75;  
    15.         int id;  
    16.           
    17.         public Printer(int id) {  
    18.             this.id = id;  
    19.         }  
    20.           
    21.         @Override  
    22.         public void run(){  
    23.             synchronized (Printer.class) {  
    24.                 while(num <= END){  
    25.                     if(num / 5 % 3 == id){ //如果是属于自己的数,依次打印出来五个  
    26.                         System.out.print(id + ":");  
    27.                         for(int i = 0; i < 5; i++){  
    28.                             System.out.print(num++ + ", ");  
    29.                         }  
    30.                         System.out.println();  
    31.                           
    32.                         Printer.class.notifyAll();//放弃CPU使用权,唤醒等待在Print.class队列上的的打印线程  
    33.                     }else{  
    34.                         try {  
    35.                             Printer.class.wait();//如果不属于自己的数,把当前线程挂在Printer.class这个对象的等待队列上(也是放弃CPU使用权),等待唤醒  
    36.                         } catch (InterruptedException e) {  
    37.                             System.out.println("id" + "被打断了");  
    38.                         }  
    39.                     }  
    40.                 }  
    41.             }  
    42.         }  
    43.     }  
    44.       
    45.       
    46.     public static void main(String[] args) {  
    47.         //下面可以不按0,1,2的顺序来,而且在两两中间随便sleep(),都会正确打印出来  
    48.         new Thread( new Printer(0)).start();  
    49.         new Thread( new Printer(1)).start();  
    50.         new Thread( new Printer(2)).start();  
    51.     }  
    52. }  

    注释中说的也很明白,有问题欢迎大家讨论。

    结果(运行了N次,结果都是一致的,请大家检验):

    Java代码  收藏代码
    1. 0:1, 2, 3, 4, 5,   
    2. 1:6, 7, 8, 9, 10,   
    3. 2:11, 12, 13, 14, 15,   
    4. 0:16, 17, 18, 19, 20,   
    5. 1:21, 22, 23, 24, 25,   
    6. 2:26, 27, 28, 29, 30,   
    7. 0:31, 32, 33, 34, 35,   
    8. 1:36, 37, 38, 39, 40,   
    9. 2:41, 42, 43, 44, 45,   
    10. 0:46, 47, 48, 49, 50,   
    11. 1:51, 52, 53, 54, 55,   
    12. 2:56, 57, 58, 59, 60,   
    13. 0:61, 62, 63, 64, 65,   
    14. 1:66, 67, 68, 69, 70,   
    15. 2:71, 72, 73, 74, 75,   

    注意第23行的synchronized (Printer.class) ,为什么是Printer.class,而不是this呢?

    是因为Print.class也是一个对象,在当前JVM中是唯一的,它相当于一个“公证人”,三个线程竞争资源的时候都是从唯一的这个“公证人”手里拿到许可,才能进入synchronized体。

    而如果是synchronized (this)的话,this也相当于一个“公证人”,那么三个线程各自有一个“公证人”,相当于各干各的,三个中间没有竞争关系,构不成同步。

    可见只要是这三个的“公证人”是同一个家伙,就能保持同步,稍微修改一下代码,我们给三个线程传进去同一个“公证人”(其实就是一个普通的不能再普通的对象):

    Java代码  收藏代码
    1. package concurrent.test;  
    2.   
    3.   
    4. /** 
    5.  * 要求创建三个线程,输出1-75, 
    6.  * 最开始第一个线程输出1-5,第二个输出6-10,第三个输出11-15 
    7.  * 接着再第一个线程输出16-20...就这样循环下去,直到打印出75个数 
    8.  * @author qiaoxueshi 
    9.  * 
    10.  */  
    11. public class Print1to75 {  
    12.     static class Printer implements Runnable{  
    13.         static int num = 1; //开始数字  
    14.         static final int END = 75;  
    15.         int id;  
    16.         Object o; //这就是三个线程的“公证人”,有点寒酸吧  
    17.           
    18.         public Printer(int id, Object o) {  
    19.             this.id = id;  
    20.             this.o = o;  
    21.         }  
    22.           
    23.         @Override  
    24.         public void run(){  
    25.             synchronized (o) {  
    26.                 while(num <= END){  
    27.                     if(num / 5 % 3 == id){ //如果是属于自己的数,依次打印出来五个  
    28.                         System.out.print(id + ":");  
    29.                         for(int i = 0; i < 5; i++){  
    30.                             System.out.print(num++ + ", ");  
    31.                         }  
    32.                         System.out.println();  
    33.                           
    34.                         o.notifyAll();//放弃CPU使用权,唤醒在o对象的等待队列上的线程  
    35.                     }else{  
    36.                         try {  
    37.                             o.wait(); //如果不属于自己的数,把当前线程挂在o这个对象的等待队列上(也放弃了CPU使用权),等待唤醒  
    38.                         } catch (InterruptedException e) {  
    39.                             System.out.println("id" + "被打断了");  
    40.                         }  
    41.                     }  
    42.                 }  
    43.             }  
    44.         }  
    45.     }  
    46.       
    47.       
    48.     public static void main(String[] args) {  
    49.         //下面可以不按0,1,2的顺序来,而且在两两中间随便sleep(),都会正确打印出来  
    50.         Object o = new Object();  
    51.         new Thread( new Printer(0, o)).start();  
    52.         new Thread( new Printer(1, o)).start();  
    53.         new Thread( new Printer(2, o)).start();  
    54.     }  
    55. }  

     

    在第16行,添加了三个线程的”公证人“ Object o;

    第25,34,37行都由原来的Printer.class改为了o;

    在第50行,创建了一个Object对象,传给了三个线程。

    运行结果和上面的是一模一样地!

    Java代码  收藏代码
    1. new Thread( new Printer(0, o)).start();  
    2. new Thread( new Printer(1, o)).start();  
    3. new Thread( new Printer(2, o)).start();  

     如果觉得这段不太优雅,可以使用ExecuorService来实现,道理是一样的。

  • 相关阅读:
    GMap.NET开发技巧 开发可以根据地图放大缩小而缩放的图元
    GPS定位数据库表设计
    基于WCF回调(WCF Callback)的GPS报警推送(带源码)
    基于部标JT/T 808协议及数据格式的GPS服务器 开发
    如何做好GPS平台软硬件集成测试
    框架内思维 创新更有力
    JT/T 808 809 部标认证流程和申报材料下载
    基于部标JT/T8092011的(已过检)GPS平台数据交换及转发服务器
    基于Spring.NET的MVC应用程序发布时的虚拟路径错误的解决方案
    javascript组件开发方式(转载)
  • 原文地址:https://www.cnblogs.com/YuyuanNo1/p/8023430.html
Copyright © 2011-2022 走看看