`
MouseLearnJava
  • 浏览: 465955 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

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

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

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

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

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


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

使用sleep
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();
	}

}


使用synchronized, wait和notifyAll

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();

				}
			}

		}

	}

}


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


使用Lock 和 Condition

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();
				}

			}
		}
	}
}



使用Semaphore
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();
			}
		}
	}
}



使用AtomicInteger

package my.thread.test;

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.println(String.format("第%d遍",
							sycValue.get() / 3 + 1));
					System.out.println("A");
					sycValue.getAndIncrement();
				}
			}

		}
	}

	private class RunnableB implements Runnable {

		public void run() {

			while (sycValue.get() < MAX_SYC_VALUE) {
				if (sycValue.get() % 3 == 1) {
					System.out.println("B");
					sycValue.getAndIncrement();
				}
			}

		}
	}

	private class RunnableC implements Runnable {

		public void run() {

			while (sycValue.get() < MAX_SYC_VALUE) {
				if (sycValue.get() % 3 == 2) {
					System.out.println("C");
					System.out.println();
					sycValue.getAndIncrement();
				}
			}

		}
	}
}


转载请注明出处http://mouselearnjava.iteye.com/blog/1949228
2
2
分享到:
评论
3 楼 jp260715007 2016-06-30  
nanjiwubing123 写道
参考你的用法,用如下方式实现。
@Slf4j
public class TestUtil {
	
	private static AtomicInteger atoIntgeger = new AtomicInteger(0);
	
	public static void multPrint(){
		ExecutorService excExecutorService = Executors.newFixedThreadPool(3);
		
		Future<Boolean> aFuture = excExecutorService.submit(new Callable<Boolean>() {
			@Override
			public Boolean call() throws Exception {
				if(atoIntgeger.get() % 3 ==0){
					atoIntgeger.getAndIncrement();
					System.out.println("A");
				}
				return true;
			}
		});
		
		Future<Boolean> bFuture = excExecutorService.submit(new Callable<Boolean>() {
			@Override
			public Boolean call() throws Exception {
				if(atoIntgeger.get() % 3 ==1){
					atoIntgeger.getAndIncrement();
					System.out.println("B");
				}
				return true;
			}
		});
		
		Future<Boolean> cFuture = excExecutorService.submit(new Callable<Boolean>() {
			@Override
			public Boolean call() throws Exception {
				if(atoIntgeger.get() % 3 ==2){
					atoIntgeger.getAndIncrement();
					System.out.println("C");
					System.out.println("\n");
				}
				return true;
			}
		});
		
	}
	

	public static void main(String[] args) throws Exception {
		log.info("------");
		int i = 0;
		while(i < 10){
			multPrint();
			i++;
			log.info(String.format("第%d次打印>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",i));
			log.info("\n");
		}
			
	}
}








   AtomicInteger版本的实现有问题,有时可以实现ABC打印10次,有的情况下最后一次只能打印出A 或AB。 
   atoIntgeger.getAndIncrement(); 能保证线程安全箱,但是几个语句组合起来,无法保证线程安全的。
2 楼 nanjiwubing123 2015-12-29  
参考你的用法,用如下方式实现。
@Slf4j
public class TestUtil {
	
	private static AtomicInteger atoIntgeger = new AtomicInteger(0);
	
	public static void multPrint(){
		ExecutorService excExecutorService = Executors.newFixedThreadPool(3);
		
		Future<Boolean> aFuture = excExecutorService.submit(new Callable<Boolean>() {
			@Override
			public Boolean call() throws Exception {
				if(atoIntgeger.get() % 3 ==0){
					atoIntgeger.getAndIncrement();
					System.out.println("A");
				}
				return true;
			}
		});
		
		Future<Boolean> bFuture = excExecutorService.submit(new Callable<Boolean>() {
			@Override
			public Boolean call() throws Exception {
				if(atoIntgeger.get() % 3 ==1){
					atoIntgeger.getAndIncrement();
					System.out.println("B");
				}
				return true;
			}
		});
		
		Future<Boolean> cFuture = excExecutorService.submit(new Callable<Boolean>() {
			@Override
			public Boolean call() throws Exception {
				if(atoIntgeger.get() % 3 ==2){
					atoIntgeger.getAndIncrement();
					System.out.println("C");
					System.out.println("\n");
				}
				return true;
			}
		});
		
	}
	

	public static void main(String[] args) throws Exception {
		log.info("------");
		int i = 0;
		while(i < 10){
			multPrint();
			i++;
			log.info(String.format("第%d次打印>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",i));
			log.info("\n");
		}
			
	}
}





1 楼 leecyz 2013-09-29  
这个题 面试时碰到几次

相关推荐

    java面试题大全(2012版)

    46、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 29 47、sleep() 和 wait() 有什么区别? 30 48、同步和异步有何异同,在什么情况下分别使用他们?举例说明...

    进入IT企业必读的200个+.NET面试题.pdf )

    ### .NET面试题详解 #### 第2章 .NET框架基础 **2.1 .NET基础概念** - **2.1.1 什么是CTS、CLS和CLR?** - **CTS (Common Type System)**:公共类型系统是.NET框架的核心组件之一,它定义了一组规则来确保所有...

    Java面试宝典-经典

    46、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 29 47、sleep() 和 wait() 有什么区别? 30 48、同步和异步有何异同,在什么情况下分别使用他们?举例说明...

    java面试宝典2012

    46、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 32 47、sleep() 和 wait() 有什么区别? 33 48、同步和异步有何异同,在什么情况下分别使用他们?举例说明...

    最新Java面试宝典pdf版

    46、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 29 47、sleep() 和 wait() 有什么区别? 30 48、同步和异步有何异同,在什么情况下分别使用他们?举例说明...

    java面试宝典

    72、当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法? 18 73、线程的基本概念、线程的基本状态以及状态之间的关系 18 74、sleep() 和 wait() 有什么区别? 18 75、socket通信...

    值得收藏的2017年Java开发岗位面试题

    7. spring注入的几种方式(循环注入)。 Spring提供了多种注入方式,例如 setter注入、构造器注入和字段注入等。 8. spring如何实现事物管理的。 Spring提供了多种事务管理机制,例如使用@Transactional注解或使用...

    Java面试宝典2012版

    46、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 29 47、sleep() 和 wait() 有什么区别? 30 48、同步和异步有何异同,在什么情况下分别使用他们?举例...

Global site tag (gtag.js) - Google Analytics