面试题--三个线程循环打印ABC10次的几种解决方法

最近发现公司有份笔试试卷中有道多线程的题目有三个线程分别打印A、B、C,请用多线程编程实现,在屏幕上循环打印10次ABCABC…

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

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

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


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

使用sleep
Java代码
  1. package my.thread.test;   
  2.   
  3. /**  
  4.  * @author Eric  
  5.  */  
  6. public class SleepExample extends Thread {   
  7.   
  8.     private static int currentCount = 0;   
  9.   
  10.     public SleepExample(String name) {   
  11.         this.setName(name);   
  12.     }   
  13.   
  14.     @Override  
  15.     public void run() {   
  16.         while (currentCount < 30) {   
  17.             switch (currentCount % 3) {   
  18.             case 0:   
  19.                 if ("A".equals(getName())) {   
  20.                     printAndIncrease();   
  21.                 }   
  22.                 break;   
  23.             case 1:   
  24.                 if ("B".equals(getName())) {   
  25.                     printAndIncrease();   
  26.                 }   
  27.                 break;   
  28.             case 2:   
  29.                 if ("C".equals(getName())) {   
  30.                     printAndIncrease();   
  31.                 }   
  32.                 break;   
  33.             }   
  34.         }   
  35.   
  36.     }   
  37.   
  38.     private void printAndIncrease() {   
  39.         print();   
  40.         increase();   
  41.     }   
  42.   
  43.     private void print() {   
  44.         System.out.println(getName());   
  45.         if ("C".equals(getName())) {   
  46.             System.out.println();   
  47.         }   
  48.     }   
  49.   
  50.     private void increase() {   
  51.         currentCount++;   
  52.     }   
  53.   
  54.     public static void main(String[] args) {   
  55.         new SleepExample("A").start();   
  56.         new SleepExample("B").start();   
  57.         new SleepExample("C").start();   
  58.     }   
  59.   
  60. }  
<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.   
  3. import java.util.concurrent.ExecutorService;   
  4. import java.util.concurrent.Executors;   
  5.   
  6. public class PrintThreadExample {   
  7.   
  8.     public static void main(String[] args) {   
  9.         PrintThreadExample example = new PrintThreadExample();   
  10.   
  11.         LetterPrinter letterPrinter = example.new LetterPrinter();   
  12.   
  13.         ExecutorService service = Executors.newFixedThreadPool(3);   
  14.   
  15.         service.execute(example.new PrintRunnable(letterPrinter, 'A'));   
  16.         service.execute(example.new PrintRunnable(letterPrinter, 'B'));   
  17.         service.execute(example.new PrintRunnable(letterPrinter, 'C'));   
  18.   
  19.         service.shutdown();   
  20.     }   
  21.   
  22.     private class LetterPrinter {   
  23.         private char letter = 'A';   
  24.   
  25.         public void print() {   
  26.             System.out.println(letter);   
  27.             if ('C' == letter) {   
  28.                 System.out.println();   
  29.             }   
  30.         }   
  31.   
  32.         public void nextLetter() {   
  33.             switch (letter) {   
  34.             case 'A':   
  35.                 letter = 'B';   
  36.                 break;   
  37.             case 'B':   
  38.                 letter = 'C';   
  39.                 break;   
  40.             case 'C':   
  41.                 letter = 'A';   
  42.                 break;   
  43.             }   
  44.         }   
  45.   
  46.         /**  
  47.          * @return the letter  
  48.          */  
  49.         public char getLetter() {   
  50.             return letter;   
  51.         }   
  52.   
  53.     }   
  54.   
  55.     private class PrintRunnable implements Runnable {   
  56.   
  57.         private LetterPrinter letterPrinter = null;   
  58.   
  59.         private char letter = ' ';   
  60.   
  61.         /**  
  62.          * @param letterPrinter  
  63.          * @param letter  
  64.          */  
  65.         public PrintRunnable(LetterPrinter letterPrinter, char letter) {   
  66.             super();   
  67.             this.letterPrinter = letterPrinter;   
  68.             this.letter = letter;   
  69.         }   
  70.   
  71.         public void run() {   
  72.             for (int i = 0; i < 10; i++) {   
  73.                 synchronized (letterPrinter) {   
  74.                     while (letter != letterPrinter.getLetter()) {   
  75.                         try {   
  76.                             letterPrinter.wait();   
  77.                         } catch (InterruptedException e) {   
  78.                             // TODO Auto-generated catch block   
  79.                             e.printStackTrace();   
  80.                         }   
  81.                     }   
  82.   
  83.                     letterPrinter.print();   
  84.                     letterPrinter.nextLetter();   
  85.                     letterPrinter.notifyAll();   
  86.   
  87.                 }   
  88.             }   
  89.   
  90.         }   
  91.   
  92.     }   
  93.   
  94. }  
<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.   
  3. import java.util.concurrent.ExecutorService;   
  4. import java.util.concurrent.Executors;   
  5. import java.util.concurrent.locks.Condition;   
  6. import java.util.concurrent.locks.Lock;   
  7. import java.util.concurrent.locks.ReentrantLock;   
  8. import java.util.logging.Logger;   
  9.   
  10. /**  
  11.  * 题目:有三个线程分别打印A、B、C,请用多线程编程实现,在屏幕上循环打印10次ABCABC…  
  12.  *   
  13.  * 本程序采用Lock和Condition来实现。  
  14.  *   
  15.  * @author Eric  
  16.  *   
  17.  */  
  18. public class ConditionExample {   
  19.   
  20.     private Lock lock = new ReentrantLock();   
  21.   
  22.     private Condition conditionA = lock.newCondition();   
  23.     private Condition conditionB = lock.newCondition();   
  24.     private Condition conditionC = lock.newCondition();   
  25.   
  26.     /** 当前线程的名字 */  
  27.     private char currentThreadName = 'A';   
  28.   
  29.     private static final Logger logger = Logger   
  30.             .getLogger("my.thread.test.OrderPrintTest");   
  31.   
  32.     public static void main(String[] args) {   
  33.   
  34.         ConditionExample ce = new ConditionExample();   
  35.   
  36.         ExecutorService service = Executors.newFixedThreadPool(3);   
  37.         service.execute(ce.new ThreadA());   
  38.         service.execute(ce.new ThreadB());   
  39.         service.execute(ce.new ThreadC());   
  40.   
  41.         service.shutdown();   
  42.     }   
  43.   
  44.     private class ThreadA implements Runnable {   
  45.         public void run() {   
  46.   
  47.             for (int i = 0; i < 10; i++) {   
  48.                 lock.lock();   
  49.                 try {   
  50.                     while (currentThreadName != 'A') {   
  51.                         try {   
  52.                             /*  
  53.                              * 如果当前线程名字不是A,那么ThreadA就处理等待状态  
  54.                              */  
  55.                             conditionA.await();   
  56.                         } catch (InterruptedException e) {   
  57.                             logger.severe(e.getLocalizedMessage());   
  58.                         }   
  59.                     }   
  60.   
  61.                     /*  
  62.                      * 打印出第几遍以及A信息  
  63.                      */  
  64.                     System.out.println(String.format("第%d遍", i + 1));   
  65.                     System.out.println("A");   
  66.   
  67.                     /*  
  68.                      * 将当前线程名置为B, 然后通知ThreadB执行  
  69.                      */  
  70.                     currentThreadName = 'B';   
  71.                     conditionB.signal();   
  72.   
  73.                 } finally {   
  74.                     lock.unlock();   
  75.                 }   
  76.             }   
  77.         }   
  78.   
  79.     }   
  80.   
  81.     private class ThreadB implements Runnable {   
  82.         public void run() {   
  83.             for (int i = 0; i < 10; i++) {   
  84.                 lock.lock();   
  85.                 try {   
  86.                     while (currentThreadName != 'B') {   
  87.                         try {   
  88.                             /*  
  89.                              * 如果当前线程名字不是B,那么ThreadB就处理等待状态  
  90.                              */  
  91.                             conditionB.await();   
  92.                         } catch (InterruptedException e) {   
  93.                             logger.severe(e.getLocalizedMessage());   
  94.                         }   
  95.                     }   
  96.   
  97.                     /*  
  98.                      * 打印信息B  
  99.                      */  
  100.                     System.out.println("B");   
  101.   
  102.                     /*  
  103.                      * 将当前线程值置为C 并通过ThreadC来执行  
  104.                      */  
  105.                     currentThreadName = 'C';   
  106.                     conditionC.signal();   
  107.   
  108.                 } finally {   
  109.                     lock.unlock();   
  110.                 }   
  111.             }   
  112.   
  113.         }   
  114.   
  115.     }   
  116.   
  117.     private class ThreadC implements Runnable {   
  118.   
  119.         public void run() {   
  120.             for (int i = 0; i < 10; i++) {   
  121.                 lock.lock();   
  122.                 try {   
  123.                     while (currentThreadName != 'C') {   
  124.                         try {   
  125.                             /*  
  126.                              * 如果当前线程名字不是C,那么ThreadC就处理等待状态  
  127.                              */  
  128.                             conditionC.await();   
  129.                         } catch (InterruptedException e) {   
  130.                             logger.severe(e.getLocalizedMessage());   
  131.                         }   
  132.                     }   
  133.   
  134.                     /*  
  135.                      * 打印信息C  
  136.                      */  
  137.                     System.out.println("C");   
  138.                     System.out.println();   
  139.   
  140.                     /*  
  141.                      * 将当前线程值置为A 并通过ThreadA来执行  
  142.                      */  
  143.                     currentThreadName = 'A';   
  144.                     conditionA.signal();   
  145.   
  146.                 } finally {   
  147.                     lock.unlock();   
  148.                 }   
  149.   
  150.             }   
  151.         }   
  152.     }   
  153. }  
<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.   
  3. import java.util.concurrent.ExecutorService;   
  4. import java.util.concurrent.Executors;   
  5. import java.util.concurrent.Semaphore;   
  6.   
  7. public class SemaphoresExample {   
  8.   
  9.     private Semaphore semaphoresA = new Semaphore(1);   
  10.     private Semaphore semaphoresB = new Semaphore(0);   
  11.     private Semaphore semaphoresC = new Semaphore(0);   
  12.   
  13.     public static void main(String[] args) {   
  14.         SemaphoresExample example = new SemaphoresExample();   
  15.         ExecutorService service = Executors.newFixedThreadPool(3);   
  16.   
  17.         service.execute(example.new RunnableA());   
  18.         service.execute(example.new RunnableB());   
  19.         service.execute(example.new RunnableC());   
  20.   
  21.         service.shutdown();   
  22.     }   
  23.   
  24.     private class RunnableA implements Runnable {   
  25.   
  26.         public void run() {   
  27.   
  28.             for (int i = 0; i < 10; i++) {   
  29.                 try {   
  30.                     semaphoresA.acquire();   
  31.                 } catch (InterruptedException e) {   
  32.                     // TODO Auto-generated catch block   
  33.                     e.printStackTrace();   
  34.                 }   
  35.                 System.out.println(String.format("第%d遍", i + 1));   
  36.                 System.out.println("A");   
  37.                 semaphoresB.release();   
  38.   
  39.             }   
  40.         }   
  41.     }   
  42.   
  43.     private class RunnableB implements Runnable {   
  44.   
  45.         public void run() {   
  46.   
  47.             for (int i = 0; i < 10; i++) {   
  48.                 try {   
  49.                     semaphoresB.acquire();   
  50.                 } catch (InterruptedException e) {   
  51.                     // TODO Auto-generated catch block   
  52.                     e.printStackTrace();   
  53.                 }   
  54.                 System.out.println("B");   
  55.                 semaphoresC.release();   
  56.             }   
  57.   
  58.         }   
  59.     }   
  60.   
  61.     private class RunnableC implements Runnable {   
  62.   
  63.         public void run() {   
  64.   
  65.             for (int i = 0; i < 10; i++) {   
  66.                 try {   
  67.                     semaphoresC.acquire();   
  68.                 } catch (InterruptedException e) {   
  69.                     // TODO Auto-generated catch block   
  70.                     e.printStackTrace();   
  71.                 }   
  72.                 System.out.println("C");   
  73.                 System.out.println();   
  74.   
  75.                 semaphoresA.release();   
  76.             }   
  77.         }   
  78.     }   
  79. }  
<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.Semaphore;

public class SemaphoresExample {

	private Semaphore semaphoresA = new Semaphore(1);
	private Semaphore semaphoresB = new Semaphore(0);
	private Semaphore semaphoresC = new Semaphore(0);

	public static void main(String[] args) {
		SemaphoresExample example = new SemaphoresExample();
		ExecutorService service = Executors.newFixedThreadPool(3);

		service.execute(example.new RunnableA());
		service.execute(example.new RunnableB());
		service.execute(example.new RunnableC());

		service.shutdown();
	}

	private class RunnableA implements Runnable {

		public void run() {

			for (int i = 0; i < 10; i++) {
				try {
					semaphoresA.acquire();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(String.format("第%d遍", i + 1));
				System.out.println("A");
				semaphoresB.release();

			}
		}
	}

	private class RunnableB implements Runnable {

		public void run() {

			for (int i = 0; i < 10; i++) {
				try {
					semaphoresB.acquire();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println("B");
				semaphoresC.release();
			}

		}
	}

	private class RunnableC implements Runnable {

		public void run() {

			for (int i = 0; i < 10; i++) {
				try {
					semaphoresC.acquire();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println("C");
				System.out.println();

				semaphoresA.release();
			}
		}
	}
}</span>



使用AtomicInteger

Java代码 复制代码
  1. package my.thread.test;   
  2.   
  3. import java.util.concurrent.ExecutorService;   
  4. import java.util.concurrent.Executors;   
  5. import java.util.concurrent.atomic.AtomicInteger;   
  6.   
  7. public class AtomicIntegerExample {   
  8.   
  9.     private AtomicInteger sycValue = new AtomicInteger(0);   
  10.   
  11.     private static final int MAX_SYC_VALUE = 3 * 10;   
  12.   
  13.     public static void main(String[] args) {   
  14.         AtomicIntegerExample example = new AtomicIntegerExample();   
  15.         ExecutorService service = Executors.newFixedThreadPool(3);   
  16.   
  17.         service.execute(example.new RunnableA());   
  18.         service.execute(example.new RunnableB());   
  19.         service.execute(example.new RunnableC());   
  20.   
  21.         service.shutdown();   
  22.     }   
  23.   
  24.     private class RunnableA implements Runnable {   
  25.   
  26.         public void run() {   
  27.   
  28.             while (sycValue.get() < MAX_SYC_VALUE) {   
  29.                 if (sycValue.get() % 3 == 0) {   
  30.                     System.out.println(String.format("第%d遍",   
  31.                             sycValue.get() / 3 + 1));   
  32.                     System.out.println("A");   
  33.                     sycValue.getAndIncrement();   
  34.                 }   
  35.             }   
  36.   
  37.         }   
  38.     }   
  39.   
  40.     private class RunnableB implements Runnable {   
  41.   
  42.         public void run() {   
  43.   
  44.             while (sycValue.get() < MAX_SYC_VALUE) {   
  45.                 if (sycValue.get() % 3 == 1) {   
  46.                     System.out.println("B");   
  47.                     sycValue.getAndIncrement();   
  48.                 }   
  49.             }   
  50.   
  51.         }   
  52.     }   
  53.   
  54.     private class RunnableC implements Runnable {   
  55.   
  56.         public void run() {   
  57.   
  58.             while (sycValue.get() < MAX_SYC_VALUE) {   
  59.                 if (sycValue.get() % 3 == 2) {   
  60.                     System.out.println("C");   
  61.                     System.out.println();   
  62.                     sycValue.getAndIncrement();   
  63.                 }   
  64.             }   
  65.   
  66.         }   
  67.     }   
  68. }  
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值