首页 > 其他分享 >三个线程循环打印ABC10次的几种解决方法

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

时间:2023-07-28 12:31:47浏览次数:39  
标签:service ABC10 void 打印 private 线程 new public

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

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

标签:service,ABC10,void,打印,private,线程,new,public
From: https://blog.51cto.com/u_14682436/6880717

相关文章

  • 关于异步多线程
    方法一:利用线程池或@Async注解使用@Async注解,可以实现多个方法并行执行,然后将它们的返回结果进行处理。@Async注解会使被标注的方法在调用时,将任务提交给一个线程池中的线程去执行,不会阻塞主线程。下面是一个简单的示例,演示如何使用@Async注解来处理多个方法的返回结果:......
  • 线程安全(一)
    什么是线程安全当多个线程同时访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那就称这个对象时线程安全的。在C#中,线程安全是指多个线程对共享资源的并发......
  • Java 打印在控制台 方法
    Java打印在控制台的方法在Java编程语言中,控制台是一种常用的输出方式。它允许程序员在调试和开发过程中查看程序的输出结果。本文将介绍几种在Java中打印输出的方法,并提供相应的代码示例。1.使用System.out.println()System.out.println()是Java中最常用的打印输出方法之一。......
  • .net core 调用打印机打印pdf文件 FreeSpire.PDF
    首先,参考了https://stackoverflow.com/questions/63941980/is-it-possible-to-print-documents-from-a-net-core-3-1-windows-service中的说明,声明:我用的是core3.1测试的先下载了FreeSpire.PDF的NuGet包,可以看出来简介上是支持print的: 然后我的测试直接在controller中:1[......
  • java 打印调用栈
    Java打印调用栈介绍在Java开发中,了解如何打印调用栈是非常重要的。调用栈(CallStack)是用于追踪程序执行期间方法的调用顺序的一种机制。通过打印调用栈,我们可以获得有关程序执行路径和调用层次的有用信息,这对于调试和问题排查非常有帮助。在本文中,我将指导你如何实现Java打印调......
  • java 打印标签源码
    Java打印标签源码实现教程作为一名经验丰富的开发者,我将教会你如何实现Java打印标签源码的功能。下面是整个实现过程的步骤:步骤实现内容步骤一连接打印机步骤二创建打印标签的模板步骤三填充标签模板数据步骤四打印标签接下来,我将详细介绍每个步骤需要......
  • java 销毁创建的线程
    Java销毁创建的线程在Java中,线程是执行程序的基本单位。我们可以通过创建线程来并发执行多个任务。然而,有时候我们需要在程序运行过程中销毁已经创建的线程。本文将讨论如何在Java中销毁创建的线程,并提供相应的代码示例。为什么要销毁线程?通常情况下,我们希望线程能够正常执行任......
  • java 线程中启动另一个线程中
    在Java线程中启动另一个线程简介在Java中,可以通过创建新的线程来实现并发执行的效果。一个线程是程序中的一个执行单元,它独立地执行指令序列。线程是轻量级的,创建和销毁线程的开销相对较小。在Java中,可以使用Thread类或者Runnable接口来创建和管理线程。步骤下面是在Java线程中......
  • jquery 打印
    jQuery打印jQuery是一个快速,简洁的JavaScript库。它简化了HTML文档遍历、事件处理、动画等操作。在本文中,我们将介绍如何使用jQuery来进行打印操作。什么是打印打印是将电子文档转换为纸质文档的过程。在Web开发中,我们经常需要将网页内容打印到纸张上,以便用户可以离线阅读或保......
  • 关于打印共享的那些事,
    今天看到一个小视频,了解到打印机共享常见连接出错问题的解决方案:注册表命令:regedit注册表目录:HKEYLOCALMACHINE\SYSTEM\CurrentControlSet\Control\Print新建32位值名称:RpcAuthnLevelPrivacyEnabled,值为0共享与被共享都要配置,重启还需要!重点来了,打印机共享终极解决......