转自: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. public class Printer implements Runnable {
  5. int id;
  6. static int num = 1;
  7. public Printer(int id) {
  8. this.id = id;
  9. }
  10. @Override
  11. public void run() {
  12. synchronized (Printer.class) {
  13. while (num <= 75) {
  14. if (num / 5 % 3 == id) {
  15. System.out.print("id" + id + ":");
  16. for (int i = 0; i < 5; i++)
  17. System.out.print(num++ + ",");
  18. System.out.println();
  19. Printer.class.notifyAll();
  20. } else {
  21. try {
  22. Printer.class.wait();
  23. } catch (InterruptedException e) {
  24. e.printStackTrace();
  25. }
  26. }
  27. }
  28. }
  29. }
  30. public static void main(String[] args) {
  31. new Thread(new Printer(0)).start();
  32. new Thread(new Printer(1)).start();
  33. new Thread(new Printer(2)).start();
  34. }
  35. }

打印结果:

  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。

直接上代码:

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

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

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

  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也相当于一个“公证人”,那么三个线程各自有一个“公证人”,相当于各干各的,三个中间没有竞争关系,构不成同步。

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

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

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

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

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

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

  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来实现,道理是一样的。

java启动3个线程轮流打印数字的更多相关文章

  1. Java n个线程轮流打印数字的问题

    一. 实现两个线程.轮流打印出数字.例如以下: bThread --> 10 aThread --> 9 bThread --> 8 aThread --> 7 bThread ...

  2. 使用Java实现三个线程交替打印0-74

    使用Java实现三个线程交替打印0-74 题目分析 三个线程交替打印,即3个线程是按顺序执行的.一个线程执行完之后,唤醒下一个线程,然后阻塞,等待被该线程的上一个线程唤醒.执行的顺序是一个环装的队列 ...

  3. Java多个线程顺序打印数字

    要求 启动N个线程, 这N个线程要不间断按顺序打印数字1-N. 将问题简化为3个线程无限循环打印1到3 方法一: 使用synchronized 三个线程无序竞争同步锁, 如果遇上的是自己的数字, 就打 ...

  4. Java之进程与线程练习

    1.设计一个线程类:创建3个子线程,每个线程分别打印数字,分别睡眠100,200,300ms ->每个执行都是20次 代码: package Homework; //1.设计一个线程类:创建3个 ...

  5. 迅雷笔试题 (JAVA多线程)启动三个线程,分别打印A B C,现在写一个程序 循环打印ABCABCABC

    题目:http://wenku.baidu.com/view/d66187aad1f34693daef3e8a.html 启动三个线程,分别打印A B C,现在写一个程序 循环打印ABCABCABC. ...

  6. 使用Java线程并发库实现两个线程交替打印的线程题

    背景:是这样的今天在地铁上浏览了以下网页,看到网上一朋友问了一个多线程的问题.晚上闲着没事就决定把它实现出来. 题目: 1.开启两个线程,一个线程打印A-Z,两一个线程打印1-52的数据. 2.实现交 ...

  7. 使用Java 多线程编程 让三个线程轮流输出ABC,循环10次后结束

    简要分析: 要求三个线程轮流输出,这里我们要使用一个对象锁,让关键部分的代码放入同步块当中.同时要有一个变量记录打印的次数到达10次循环后不再打印,另外一个就是要给每个线程一个标志号,我们根据标识号来 ...

  8. Java 启动线程的方式

    面试题:JAVA启动线程的方式有哪些? 1.继承Thread [java] view plaincopy public class java_thread extends Thread{ public ...

  9. Java线程同步打印ABC

    需求: 三个线程,依次打印ABCABCABC.... 方案一: 使用阻塞队列,线程1从队列1获取内容打印,线程2从队列2获取内容打印,线程3从队列3中获取内容打印.线程1把B放到队列3中,线程2把C放 ...

随机推荐

  1. ASP.NET C# 获取当前日期 时间 年 月 日 时 分 秒

    我们可以通过使用DataTime这个类来获取当前的时间.通过调用类中的各种方法我们可以获取不同的时间:如:日期(2008-09-04).时间(12:12:12).日期+时间(2008-09-04 12 ...

  2. r语言与dataframe

    什么是DataFrame 引用 r-tutor上的定义: DataFrame 是一个表格或者类似二维数组的结构,它的各行表示一个实例,各列表示一个变量. 没错,DataFrame就是类似于Excel表 ...

  3. 也谈谈js的压缩,jquery压缩。【转】

    问题缘由: 负责公司的开发平台研发工作,考虑的知识产权的保护工作,必须要考虑java的加密技术和js脚本的加密技术.在目前java加密很容易破解的情况下,还是先搞定js的加密和压缩,一方面可以提高页面 ...

  4. Kafka Tools

    参考, https://cwiki.apache.org/confluence/display/KAFKA/System+Tools https://cwiki.apache.org/confluen ...

  5. Java 经典问题

    九种基本类型及封装类 基本类型 boolean byte char short int long double void 二进制位数 1 8(一字节) 16(2字节) 16(2字节) 32(4字节) ...

  6. oop-Inheritance & Polymorphism

    本文主要作为java学习笔记,方便以后查看,大部分内容都源于以下网站: http://www.ntu.edu.sg/home/ehchua/programming/index.html#Game 本文 ...

  7. Windows下 flex + bison 小例子

    .下载flex和bison,网址是http://gnuwin32.sourceforge.net/packages/flex.htm 和http://gnuwin32.sourceforge.net/ ...

  8. e641. 使一个组件成为拖放目标

    public class DropTargetComponent extends JComponent implements DropTargetListener { public DropTarge ...

  9. 《Java程序猿面试笔试宝典》之组合与继承有什么差别

    组合和继承是面向对象中两种代码复用的方式. 组合是指在新类里面创建原有类的对象,反复利用已有类的功能.继承是面向对象的主要特性之中的一个,它同意设计人员依据其他类的实现来定义一个类的实现. 组合和继承 ...

  10. 转载:erlang程序优化点的总结

    erlang程序优化点的总结(持续更新) 转自:http://wqtn22.iteye.com/blog/1820587 转载请注明出处 注意,这里只是给出一个总结,具体性能需要根据实际环境和需要来确 ...