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

≡放荡痞女 提交于 2019-12-06 03:18:05

有三个线程分别打印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.... 

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!