多线程打印abc

面试题--三个线程循环打印ABC10次的几种解决方法
博客分类:多线程 Java 面试题 多线程 java thread Semaphore Condition最近发现公司有份笔试试卷中有道多线程的 题目: 有三个线程分别打印A、B、C,请用多线程编程实现,在屏幕上循环打印10次ABCABC…

这个最早好像是迅雷的面试题目吧,看到了然后就想重温一下这个题目的解决方法。

在本文中,给出了五种这个题目的解决方法:

  • 使用sleep
  • 使用synchronized, wait和notifyAll
  • 使用Lock 和 Condition
  • 使用Semaphore
  • 使用AtomicInteger


下面依次给出每种解决方案的代码:

使用sleep
Java代码多线程打印abc
文章图片
  1. package my.thread.test;
  2. /**
  3. * @author Eric
  4. */
  5. public class SleepExample extends Thread {
  6. private static int currentCount = 0;
  7. public SleepExample(String name) {
  8. this.setName(name);
  9. }
  10. @Override
  11. public void run() {
  12. while (currentCount < 30) {
  13. switch (currentCount % 3) {
  14. case 0:
  15. if ("A".equals(getName())) {
  16. printAndIncrease();
  17. }
  18. break;
  19. case 1:
  20. if ("B".equals(getName())) {
  21. printAndIncrease();
  22. }
  23. break;
  24. case 2:
  25. if ("C".equals(getName())) {
  26. printAndIncrease();
  27. }
  28. break;
  29. }
  30. }
  31. }
  32. private void printAndIncrease() {
  33. print();
  34. increase();
  35. }
  36. private void print() {
  37. System.out.println(getName());
  38. if ("C".equals(getName())) {
  39. System.out.println();
  40. }
  41. }
  42. private void increase() {
  43. currentCount++;
  44. }
  45. public static void main(String[] args) {
  46. new SleepExample("A").start();
  47. new SleepExample("B").start();
  48. new SleepExample("C").start();
  49. }
  50. }


使用synchronized, wait和notifyAll

Java代码多线程打印abc
文章图片
  1. package my.thread.test;
  2. import java.util.concurrent.ExecutorService;
  3. import java.util.concurrent.Executors;
  4. public class PrintThreadExample {
  5. public static void main(String[] args) {
  6. PrintThreadExample example = new PrintThreadExample();
  7. LetterPrinter letterPrinter = example.new LetterPrinter();
  8. ExecutorService service = Executors.newFixedThreadPool(3);
  9. service.execute(example.new PrintRunnable(letterPrinter, 'A'));
  10. service.execute(example.new PrintRunnable(letterPrinter, 'B'));
  11. service.execute(example.new PrintRunnable(letterPrinter, 'C'));
  12. service.shutdown();
  13. }
  14. private class LetterPrinter {
  15. private char letter = 'A';
  16. public void print() {
  17. System.out.println(letter);
  18. if ('C' == letter) {
  19. System.out.println();
  20. }
  21. }
  22. public void nextLetter() {
  23. switch (letter) {
  24. case 'A':
  25. letter = 'B';
  26. break;
  27. case 'B':
  28. letter = 'C';
  29. break;
  30. case 'C':
  31. letter = 'A';
  32. break;
  33. }
  34. }
  35. /**
  36. * @return the letter
  37. */
  38. public char getLetter() {
  39. return letter;
  40. }
  41. }
  42. private class PrintRunnable implements Runnable {
  43. private LetterPrinter letterPrinter = null;
  44. private char letter = ' ';
  45. /**
  46. * @param letterPrinter
  47. * @param letter
  48. */
  49. public PrintRunnable(LetterPrinter letterPrinter, char letter) {
  50. super();
  51. this.letterPrinter = letterPrinter;
  52. this.letter = letter;
  53. }
  54. public void run() {
  55. for (int i = 0; i < 10; i++) {
  56. synchronized (letterPrinter) {
  57. while (letter != letterPrinter.getLetter()) {
  58. try {
  59. letterPrinter.wait();
  60. } catch (InterruptedException e) {
  61. // TODO Auto-generated catch block
  62. e.printStackTrace();
  63. }
  64. }
  65. letterPrinter.print();
  66. letterPrinter.nextLetter();
  67. letterPrinter.notifyAll();
  68. }
  69. }
  70. }
  71. }
  72. }


JDK 1.5 引入J.U.C包之后,也给我们提供了更多实现多线程程序的选择: Condition, 原子类AtomicInteger以及Semaphore等。


使用Lock 和 Condition

Java代码多线程打印abc
文章图片
  1. package my.thread.test;
  2. import java.util.concurrent.ExecutorService;
  3. import java.util.concurrent.Executors;
  4. import java.util.concurrent.locks.Condition;
  5. import java.util.concurrent.locks.Lock;
  6. import java.util.concurrent.locks.ReentrantLock;
  7. import java.util.logging.Logger;
  8. /**
  9. * 题目:有三个线程分别打印A、B、C,请用多线程编程实现,在屏幕上循环打印10次ABCABC…
  10. *
  11. * 本程序采用Lock和Condition来实现。
  12. *
  13. * @author Eric
  14. *
  15. */
  16. public class ConditionExample {
  17. private Lock lock = new ReentrantLock();
  18. private Condition conditionA = lock.newCondition();
  19. private Condition conditionB = lock.newCondition();
  20. private Condition conditionC = lock.newCondition();
  21. /** 当前线程的名字 */
  22. private char currentThreadName = 'A';
  23. private static final Logger logger = Logger
  24. .getLogger("my.thread.test.OrderPrintTest");
  25. public static void main(String[] args) {
  26. ConditionExample ce = new ConditionExample();
  27. ExecutorService service = Executors.newFixedThreadPool(3);
  28. service.execute(ce.new ThreadA());
  29. service.execute(ce.new ThreadB());
  30. service.execute(ce.new ThreadC());
  31. service.shutdown();
  32. }
  33. private class ThreadA implements Runnable {
  34. public void run() {
  35. for (int i = 0; i < 10; i++) {
  36. lock.lock();
  37. try {
  38. while (currentThreadName != 'A') {
  39. try {
  40. /*
  41. * 如果当前线程名字不是A,那么ThreadA就处理等待状态
  42. */
  43. conditionA.await();
  44. } catch (InterruptedException e) {
  45. logger.severe(e.getLocalizedMessage());
  46. }
  47. }
  48. /*
  49. * 打印出第几遍以及A信息
  50. */
  51. System.out.println(String.format("第%d遍", i + 1));
  52. System.out.println("A");
  53. /*
  54. * 将当前线程名置为B, 然后通知ThreadB执行
  55. */
  56. currentThreadName = 'B';
  57. conditionB.signal();
  58. } finally {
  59. lock.unlock();
  60. }
  61. }
  62. }
  63. }
  64. private class ThreadB implements Runnable {
  65. public void run() {
  66. for (int i = 0; i < 10; i++) {
  67. lock.lock();
  68. try {
  69. while (currentThreadName != 'B') {
  70. try {
  71. /*
  72. * 如果当前线程名字不是B,那么ThreadB就处理等待状态
  73. */
  74. conditionB.await();
  75. } catch (InterruptedException e) {
  76. logger.severe(e.getLocalizedMessage());
  77. }
  78. }
  79. /*
  80. * 打印信息B
  81. */
  82. System.out.println("B");
  83. /*
  84. * 将当前线程值置为C 并通过ThreadC来执行
  85. */
  86. currentThreadName = 'C';
  87. conditionC.signal();
  88. } finally {
  89. lock.unlock();
  90. }
  91. }
  92. }
  93. }
  94. private class ThreadC implements Runnable {
  95. public void run() {
  96. for (int i = 0; i < 10; i++) {
  97. lock.lock();
  98. try {
  99. while (currentThreadName != 'C') {
  100. try {
  101. /*
  102. * 如果当前线程名字不是C,那么ThreadC就处理等待状态
  103. */
  104. conditionC.await();
  105. } catch (InterruptedException e) {
  106. logger.severe(e.getLocalizedMessage());
  107. }
  108. }
  109. /*
  110. * 打印信息C
  111. */
  112. System.out.println("C");
  113. System.out.println();
  114. /*
  115. * 将当前线程值置为A 并通过ThreadA来执行
  116. */
  117. currentThreadName = 'A';
  118. conditionA.signal();
  119. } finally {
  120. lock.unlock();
  121. }
  122. }
  123. }
  124. }
  125. }



使用Semaphore
Java代码多线程打印abc
文章图片
  1. package my.thread.test;
  2. import java.util.concurrent.ExecutorService;
  3. import java.util.concurrent.Executors;
  4. import java.util.concurrent.Semaphore;
  5. public class SemaphoresExample {
  6. private Semaphore semaphoresA = new Semaphore(1);
  7. private Semaphore semaphoresB = new Semaphore(0);
  8. private Semaphore semaphoresC = new Semaphore(0);
  9. public static void main(String[] args) {
  10. SemaphoresExample example = new SemaphoresExample();
  11. ExecutorService service = Executors.newFixedThreadPool(3);
  12. service.execute(example.new RunnableA());
  13. service.execute(example.new RunnableB());
  14. service.execute(example.new RunnableC());
  15. service.shutdown();
  16. }
  17. private class RunnableA implements Runnable {
  18. public void run() {
  19. for (int i = 0; i < 10; i++) {
  20. try {
  21. semaphoresA.acquire();
  22. } catch (InterruptedException e) {
  23. // TODO Auto-generated catch block
  24. e.printStackTrace();
  25. }
  26. System.out.println(String.format("第%d遍", i + 1));
  27. System.out.println("A");
  28. semaphoresB.release();
  29. }
  30. }
  31. }
  32. private class RunnableB implements Runnable {
  33. public void run() {
  34. for (int i = 0; i < 10; i++) {
  35. try {
  36. semaphoresB.acquire();
  37. } catch (InterruptedException e) {
  38. // TODO Auto-generated catch block
  39. e.printStackTrace();
  40. }
  41. System.out.println("B");
  42. semaphoresC.release();
  43. }
  44. }
  45. }
  46. private class RunnableC implements Runnable {
  47. public void run() {
  48. for (int i = 0; i < 10; i++) {
  49. try {
  50. semaphoresC.acquire();
  51. } catch (InterruptedException e) {
  52. // TODO Auto-generated catch block
  53. e.printStackTrace();
  54. }
  55. System.out.println("C");
  56. System.out.println();
  57. semaphoresA.release();
  58. }
  59. }
  60. }
  61. }
【多线程打印abc】

    推荐阅读