0
点赞
收藏
分享

微信扫一扫

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

有三个线程分别打印A、B、C, 请用多线程编程实现,在屏幕上循环打印10次ABCABC… 

这是一个比较常用的关于线程的考题,一般出现在应届生的校园招聘试卷上。

本文给出如下四种解决方法:

  1. 使用synchronized, wait和notifyAll
  2. 使用Lock 和 Condition
  3. 使用Semaphore
  4. 使用AtomicInteger


使用synchronized, wait和notifyAll

/**
  * @author wangmengjun
  *
  */
 public class SyncObj {
  
 	private char letter = 'A';
  
 	public void nextLetter() {
 		switch (letter) {
 		case 'A':
 			letter = 'B';
 			break;
 		case 'B':
 			letter = 'C';
 			break;
 		case 'C':
 			letter = 'A';
 			break;
 		default:
 			break;
 		}
 	}
  
 	public char getLetter() {
 		return letter;
 	}
  
 }

 

/**
  * @author wangmengjun
  *
  */
 public class PrintLetterRunnable implements Runnable {
  
 	private SyncObj syncObj;
  
 	private char letter;
  
 	public PrintLetterRunnable(SyncObj syncObj, char letter) {
 		this.syncObj = syncObj;
 		this.letter = letter;
 	}
  
 	public void run() {
 		for (int i = 0; i < 10; i++) {
 			synchronized (syncObj) {
 				/**
 				 * 如果当前线程的字符和同步对象的字符不一致,则当前线程一直等待
 				 */
 				while (letter != syncObj.getLetter()) {
 					try {
 						syncObj.wait();
 					} catch (InterruptedException e) {
 						// TODO Auto-generated catch block
 						e.printStackTrace();
 					}
 				}
  
 				/**
 				 * 输出当前线程的字符
 				 */
 				System.out.print(letter);
  
 				/**
 				 * 改变同步对象的letter值
 				 */
 				syncObj.nextLetter();
  
 				/**
 				 * 通知其它所有等待线程
 				 */
 				syncObj.notifyAll();
  
 			}
 		}
 	}
  
 }

 

public class Main {
  
 	public static void main(String[] args) {
 		
 		SyncObj syncObj = new SyncObj();
  
 		Thread threadA = new Thread(new PrintLetterRunnable(syncObj, 'A'));
 		Thread threadB = new Thread(new PrintLetterRunnable(syncObj, 'B'));
 		Thread threadC = new Thread(new PrintLetterRunnable(syncObj, 'C'));
  
 		threadA.start();
 		threadB.start();
 		threadC.start();
  
 	}
 }

ABCABCABCABCABCABCABCABCABCABC

 


使用Lock 和 Condition

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

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;
  
 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';
  
 	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) {
 							e.printStackTrace();
 						}
 					}
  
 					System.out.print("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) {
 							e.printStackTrace();
 						}
 					}
  
 					/**
 					 * 打印信息B
 					 */
 					System.out.print("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) {
 							e.printStackTrace();
 						}
 					}
  
 					/**
 					 * 打印信息C
 					 */
 					System.out.print("C");
  
 					/**
 					 * 将当前线程值置为A 并通过ThreadA来执行
 					 */
 					currentThreadName = 'A';
 					conditionA.signal();
  
 				} finally {
 					lock.unlock();
 				}
  
 			}
 		}
 	}
  
 }

 


使用Semaphore

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) {
 					e.printStackTrace();
 				}
 				System.out.print("A");
 				semaphoresB.release();
  
 			}
 		}
 	}
  
 	private class RunnableB implements Runnable {
  
 		public void run() {
 			for (int i = 0; i < 10; i++) {
 				try {
 					semaphoresB.acquire();
 				} catch (InterruptedException e) {
 					e.printStackTrace();
 				}
 				System.out.print("B");
 				semaphoresC.release();
 			}
 		}
 	}
  
 	private class RunnableC implements Runnable {
 		public void run() {
  
 			for (int i = 0; i < 10; i++) {
 				try {
 					semaphoresC.acquire();
 				} catch (InterruptedException e) {
 					e.printStackTrace();
 				}
 				System.out.print("C");
 				semaphoresA.release();
 			}
 		}
 	}
 }


使用AtomicInteger

import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.atomic.AtomicInteger;
  
 public class AtomicIntegerExample {
  
 	private AtomicInteger sycValue = new AtomicInteger(0);
  
 	private static final int MAX_SYC_VALUE = 3 * 10;
  
 	public static void main(String[] args) {
 		
 		AtomicIntegerExample example = new AtomicIntegerExample();
 		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() {
 			while (sycValue.get() < MAX_SYC_VALUE) {
 				if (sycValue.get() % 3 == 0) {
 					System.out.print("A");
 					sycValue.getAndIncrement();
 				}
 			}
  
 		}
 	}
  
 	private class RunnableB implements Runnable {
 		public void run() {
 			while (sycValue.get() < MAX_SYC_VALUE) {
 				if (sycValue.get() % 3 == 1) {
 					System.out.print("B");
 					sycValue.getAndIncrement();
 				}
 			}
  
 		}
 	}
  
 	private class RunnableC implements Runnable {
 		public void run() {
 			while (sycValue.get() < MAX_SYC_VALUE) {
 				if (sycValue.get() % 3 == 2) {
 					System.out.print("C");
 					sycValue.getAndIncrement();
 				}
 			}
  
 		}
 	}
 }


小结

有三个线程分别打印A、B、C, 请用多线程编程实现,在屏幕上循环打印10次ABCABC… 

如上题目解答的方法有多种,本文只给出了几种比较常用的解法。

掌握本文提供的几个方法,那么,类似的题目按照这个思路,也是可以解决的。

如:

一个线程打印 1~52,另一个线程打印字母A-Z。打印顺序为12A34B56C……5152Z。 

再如:

有四个线程1、2、3、4。线程1的功能就是输出A,线程2的功能就是输出B,以此类推......... 现在有四个文件file1,file2,file3, file4。初始都为空。 

现要让四个文件呈如下格式: 
 file1:A B C D A B.... 
 file2:B C D A B C.... 
 file3:C D A B C D.... 
 file4:D A B C D A....

这些题目都是相似相通的,有兴趣的朋友可以自己编写一下试试。

举报

相关推荐

0 条评论