有三个线程分别打印A、B、C, 请用多线程编程实现,在屏幕上循环打印10次ABCABC…
这是一个比较常用的关于线程的考题,一般出现在应届生的校园招聘试卷上。
本文给出如下四种解决方法:
- 使用synchronized, wait和notifyAll
- 使用Lock 和 Condition
- 使用Semaphore
- 使用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....
这些题目都是相似相通的,有兴趣的朋友可以自己编写一下试试。
来源:oschina
链接:https://my.oschina.net/u/2911530/blog/778798