1. 程式人生 > >面試題--三個執行緒迴圈列印ABC10次的幾種解決方法

面試題--三個執行緒迴圈列印ABC10次的幾種解決方法

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


下面依次給出每種解決方案的程式碼:

使用sleep
Java程式碼
  1. package my.thread.test;   
  2. /**  
  3.  * @author Eric  
  4.  */
  5. publicclass SleepExample extends Thread {   
  6. privatestaticint currentCount = 0;   
  7. public SleepExample(String name) {   
  8. this
    .setName(name);   
  9.     }   
  10. @Override
  11. publicvoid run() {   
  12. while (currentCount < 30) {   
  13. switch (currentCount % 3) {   
  14. case0:   
  15. if ("A".equals(getName())) {   
  16.                     printAndIncrease();   
  17.                 }   
  18. break;   
  19. case1:   
  20. if ("B".equals(getName())) {   
  21.                     printAndIncrease();   
  22.                 }   
  23. break;   
  24. case2:   
  25. if ("C".equals(getName())) {   
  26.                     printAndIncrease();   
  27.                 }   
  28. break;   
  29.             }   
  30.         }   
  31.     }   
  32. privatevoid printAndIncrease() {   
  33.         print();   
  34.         increase();   
  35.     }   
  36. privatevoid print() {   
  37.         System.out.println(getName());   
  38. if ("C".equals(getName())) {   
  39.             System.out.println();   
  40.         }   
  41.     }   
  42. privatevoid increase() {   
  43.         currentCount++;   
  44.     }   
  45. publicstaticvoid main(String[] args) {   
  46. new SleepExample("A").start();   
  47. new SleepExample("B").start();   
  48. new SleepExample("C").start();   
  49.     }   
  50. }  
<span style="font-family:KaiTi_GB2312;font-size:18px;">package my.thread.test;

/**
 * @author Eric
 */
public class SleepExample extends Thread {

	private static int currentCount = 0;

	public SleepExample(String name) {
		this.setName(name);
	}

	@Override
	public void run() {
		while (currentCount < 30) {
			switch (currentCount % 3) {
			case 0:
				if ("A".equals(getName())) {
					printAndIncrease();
				}
				break;
			case 1:
				if ("B".equals(getName())) {
					printAndIncrease();
				}
				break;
			case 2:
				if ("C".equals(getName())) {
					printAndIncrease();
				}
				break;
			}
		}

	}

	private void printAndIncrease() {
		print();
		increase();
	}

	private void print() {
		System.out.println(getName());
		if ("C".equals(getName())) {
			System.out.println();
		}
	}

	private void increase() {
		currentCount++;
	}

	public static void main(String[] args) {
		new SleepExample("A").start();
		new SleepExample("B").start();
		new SleepExample("C").start();
	}

}</span>


使用synchronized, wait和notifyAll

Java程式碼 複製程式碼
  1. package my.thread.test;   
  2. import java.util.concurrent.ExecutorService;   
  3. import java.util.concurrent.Executors;   
  4. publicclass PrintThreadExample {   
  5. publicstaticvoid 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. privateclass LetterPrinter {   
  15. privatechar letter = 'A';   
  16. publicvoid print() {   
  17.             System.out.println(letter);   
  18. if ('C' == letter) {   
  19.                 System.out.println();   
  20.             }   
  21.         }   
  22. publicvoid 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. publicchar getLetter() {   
  39. return letter;   
  40.         }   
  41.     }   
  42. privateclass PrintRunnable implements Runnable {   
  43. private LetterPrinter letterPrinter = null;   
  44. privatechar 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. publicvoid 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. }  
<span style="font-family:KaiTi_GB2312;font-size:18px;">package my.thread.test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class PrintThreadExample {

	public static void main(String[] args) {
		PrintThreadExample example = new PrintThreadExample();

		LetterPrinter letterPrinter = example.new LetterPrinter();

		ExecutorService service = Executors.newFixedThreadPool(3);

		service.execute(example.new PrintRunnable(letterPrinter, 'A'));
		service.execute(example.new PrintRunnable(letterPrinter, 'B'));
		service.execute(example.new PrintRunnable(letterPrinter, 'C'));

		service.shutdown();
	}

	private class LetterPrinter {
		private char letter = 'A';

		public void print() {
			System.out.println(letter);
			if ('C' == letter) {
				System.out.println();
			}
		}

		public void nextLetter() {
			switch (letter) {
			case 'A':
				letter = 'B';
				break;
			case 'B':
				letter = 'C';
				break;
			case 'C':
				letter = 'A';
				break;
			}
		}

		/**
		 * @return the letter
		 */
		public char getLetter() {
			return letter;
		}

	}

	private class PrintRunnable implements Runnable {

		private LetterPrinter letterPrinter = null;

		private char letter = ' ';

		/**
		 * @param letterPrinter
		 * @param letter
		 */
		public PrintRunnable(LetterPrinter letterPrinter, char letter) {
			super();
			this.letterPrinter = letterPrinter;
			this.letter = letter;
		}

		public void run() {
			for (int i = 0; i < 10; i++) {
				synchronized (letterPrinter) {
					while (letter != letterPrinter.getLetter()) {
						try {
							letterPrinter.wait();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}

					letterPrinter.print();
					letterPrinter.nextLetter();
					letterPrinter.notifyAll();

				}
			}

		}

	}

}</span>


JDK 1.5 引入J.U.C包之後,也給我們提供了更多實現多執行緒程式的選擇: Condition, 原子類AtomicInteger以及Semaphore等。


使用Lock 和 Condition
Java程式碼 複製程式碼
  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. publicclass 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. privatechar currentThreadName = 'A';   
  23. privatestaticfinal Logger logger = Logger   
  24.             .getLogger("my.thread.test.OrderPrintTest");   
  25. publicstaticvoid 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. privateclass ThreadA implements Runnable {   
  34. publicvoid 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. privateclass ThreadB implements Runnable {   
  65. publicvoid 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. privateclass ThreadC implements Runnable {   
  95. publicvoid 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. }  
<span style="font-family:KaiTi_GB2312;font-size:18px;">package my.thread.test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Logger;

/**
 * 題目:有三個執行緒分別列印A、B、C,請用多執行緒程式設計實現,在螢幕上迴圈列印10次ABCABC…
 * 
 * 本程式採用Lock和Condition來實現。
 * 
 * @author Eric
 * 
 */
public class ConditionExample {

	private Lock lock = new ReentrantLock();

	private Condition conditionA = lock.newCondition();
	private Condition conditionB = lock.newCondition();
	private Condition conditionC = lock.newCondition();

	/** 當前執行緒的名字 */
	private char currentThreadName = 'A';

	private static final Logger logger = Logger
			.getLogger("my.thread.test.OrderPrintTest");

	public static void main(String[] args) {

		ConditionExample ce = new ConditionExample();

		ExecutorService service = Executors.newFixedThreadPool(3);
		service.execute(ce.new ThreadA());
		service.execute(ce.new ThreadB());
		service.execute(ce.new ThreadC());

		service.shutdown();
	}

	private class ThreadA implements Runnable {
		public void run() {

			for (int i = 0; i < 10; i++) {
				lock.lock();
				try {
					while (currentThreadName != 'A') {
						try {
							/*
							 * 如果當前執行緒名字不是A,那麼ThreadA就處理等待狀態
							 */
							conditionA.await();
						} catch (InterruptedException e) {
							logger.severe(e.getLocalizedMessage());
						}
					}

					/*
					 * 打印出第幾遍以及A資訊
					 */
					System.out.println(String.format("第%d遍", i + 1));
					System.out.println("A");

					/*
					 * 將當前執行緒名置為B, 然後通知ThreadB執行
					 */
					currentThreadName = 'B';
					conditionB.signal();

				} finally {
					lock.unlock();
				}
			}
		}

	}

	private class ThreadB implements Runnable {
		public void run() {
			for (int i = 0; i < 10; i++) {
				lock.lock();
				try {
					while (currentThreadName != 'B') {
						try {
							/*
							 * 如果當前執行緒名字不是B,那麼ThreadB就處理等待狀態
							 */
							conditionB.await();
						} catch (InterruptedException e) {
							logger.severe(e.getLocalizedMessage());
						}
					}

					/*
					 * 列印資訊B
					 */
					System.out.println("B");

					/*
					 * 將當前執行緒值置為C 並通過ThreadC來執行
					 */
					currentThreadName = 'C';
					conditionC.signal();

				} finally {
					lock.unlock();
				}
			}

		}

	}

	private class ThreadC implements Runnable {

		public void run() {
			for (int i = 0; i < 10; i++) {
				lock.lock();
				try {
					while (currentThreadName != 'C') {
						try {
							/*
							 * 如果當前執行緒名字不是C,那麼ThreadC就處理等待狀態
							 */
							conditionC.await();
						} catch (InterruptedException e) {
							logger.severe(e.getLocalizedMessage());
						}
					}

					/*
					 * 列印資訊C
					 */
					System.out.println("C");
					System.out.println();

					/*
					 * 將當前執行緒值置為A 並通過ThreadA來執行
					 */
					currentThreadName = 'A';
					conditionA.signal();

				} finally {
					lock.unlock();
				}

			}
		}
	}
}</span>



使用Semaphore
Java程式碼 複製程式碼
  1. package my.thread.test;   
  2. import java.util.concurrent.ExecutorService;   
  3. import java.util.concurrent.Executors;   
  4. import java.util.concurrent.Semaphore;   
  5. publicclass SemaphoresExample {   
  6. private Semaphore semaphoresA = new Semaphore(1);   
  7. private