文档章节

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

王孟君
 王孟君
发布于 2016/10/31 20:01
字数 1095
阅读 795
收藏 3

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

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

© 著作权归作者所有

王孟君

王孟君

粉丝 227
博文 94
码字总数 221044
作品 0
杭州
高级程序员
私信 提问
java多线程编程之连续打印abc的几种解法

一道编程题如下: 实例化三个线程,一个线程打印a,一个线程打印b,一个线程打印c,三个线程同时执行,要求打印出10个连着的abc。 题目分析: 通过题意我们可以得出,本题需要我们使用三个线...

文文1
06/01
25
0
JAVA wait(), notify(),sleep详解

在JAVA中,是没有类似于PV操作、进程互斥等相关的方法的。JAVA的进程同步是通过synchronized()来实现的,需要说明的是,JAVA的synchronized()方法类似于操作系统概念中的互斥内存块,在JAVA中...

choulanlan
2016/07/13
0
0
Java多线程剖析

问题的缘由源自于一道简单的面试题:题目要求如下: 建立三个线程,A线程打印10次A,B线程打印10次B,C线程打印10次C,要求线程同时运行,交替打印10次ABC。 解决问题前我们前补充一些基本知识...

wf王帆
2016/07/20
52
0
java中进程同步浅谈(磨砺营马剑威java)

Java 代码public class MyThreadPrinter2 implements Runnable { } Java代码 public void run() { } Java代码 public class MyThreadPrinter2 implements Runnable { }......

磨砺营
2016/08/22
130
0
java中同步的实现(磨砺营马剑威java)

Java代码 public class MyThreadPrinter2 implements Runnable { private String name; private Object prev; private Object self; private MyThreadPrinter2(String name, Object prev, Ob......

磨砺营
2016/08/25
14
0

没有更多内容

加载失败,请刷新页面

加载更多

golang-字符串-地址分析

demo package mainimport "fmt"func main() {str := "map.baidu.com"fmt.Println(&str, str)str = str[0:5]fmt.Println(&str, str)str = "abc"fmt.Println(&s......

李琼涛
今天
4
0
Spring Boot WebFlux 增删改查完整实战 demo

03:WebFlux Web CRUD 实践 前言 上一篇基于功能性端点去创建一个简单服务,实现了 Hello 。这一篇用 Spring Boot WebFlux 的注解控制层技术创建一个 CRUD WebFlux 应用,让开发更方便。这里...

泥瓦匠BYSocket
今天
9
0
从0开始学FreeRTOS-(列表与列表项)-3

FreeRTOS列表&列表项的源码解读 第一次看列表与列表项的时候,感觉很像是链表,虽然我自己的链表也不太会,但是就是感觉很像。 在FreeRTOS中,列表与列表项使用得非常多,是FreeRTOS的一个数...

杰杰1号
今天
9
0
Java反射

Java 反射 反射是框架设计的灵魂(使用的前提条件:必须先得到代表的字节码的 Class,Class 类 用于表示.class 文件(字节码)) 一、反射的概述 定义:JAVA 反射机制是在运行状态中,对于任...

zzz1122334
今天
9
0
聊聊nacos的LocalConfigInfoProcessor

序 本文主要研究一下nacos的LocalConfigInfoProcessor LocalConfigInfoProcessor nacos-1.1.3/client/src/main/java/com/alibaba/nacos/client/config/impl/LocalConfigInfoProcessor.java p......

go4it
昨天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部