多个线程分别顺序交替打印一种不同字符abcdefg(已实现随便多少个线程打印多少个字符,利用线程池实现多线程)
下面实现多线程顺序打印字符"abcdefg";
实现Runnable接口:
/**
* @author: rhyme
* @date: 2019-08-17 14:39
* @topic: "Runnable"
* @description: "每个线程通过sign表示需要打印的字符数组下标,index表示将要打印的字符数组的下标"
*/
public class PrintRunnable implements Runnable { private final char[] chars;
/**
* 当前线程只能打印的那个字符对应数组的下标
*/
private final int sign;
/**
* 当前将要打印的字符数组下标
*/
private volatile static int index; private final static Class<PrintRunnable> CLASS_LOCK = PrintRunnable.class; public PrintRunnable(String chars, int sign) {
this.chars = chars.toCharArray();
this.sign = sign;
} @Override
public void run() {
try {
while (true) {
// 为了结合线程池shutdownNow方法设置中断interrupt停止线程
/*if (Thread.currentThread().isInterrupted()) {
break;
}*/ synchronized (CLASS_LOCK) {
if (index % chars.length == sign) {
System.out.printf("ThreadName : %s is printing (%c)\n", Thread.currentThread().getName(), chars[sign]);
index++;
CLASS_LOCK.notifyAll();
} CLASS_LOCK.wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
System.err.printf("ThreadName : %s InterruptedException\n", Thread.currentThread().getName());
}
}
}
这里实现Runnable接口,两个重要的属性sign和index;
sign表示当前线程打印的那个字符在字符数组中的下标;
index表示移动字符下标打印, index % chars.length(重要,顺序打印的核心实现)的值表示需要打印的字符的下标,当一个字符被打印,index++;
chars表示一个字符数组;
wait()这里有两个作用,一个是为了让当前线程等待不马上循环获取锁影响效率,另一个可以通过设置线程中断interrupt抛异常停止;
notifyAll唤醒所有对应锁wait()的线程;
这里也可以不用wait和notifyAll,那每个线程就不会wait,重复循环获取锁,占用资源影响效率,其次可判断线程是否被设为中断,则break退出循环。
利用线程池启动:
import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.util.concurrent.*; /**
* @author: rhyme
* @date: 2019-08-17 14:37
* @topic: "多个线程打印"
* @description: "多个线程有序打印abcdefg"
*/
public class MultiThreadPrintOrder {
public static void main(String[] args) throws InterruptedException {
final String string = "abcdefg"; ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("order-pool-%d")
.build(); ExecutorService threadPoolExecutor =
new ThreadPoolExecutor(
string.length(),
string.length(),
0L,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1),
namedThreadFactory,
new ThreadPoolExecutor.AbortPolicy()); for (int i = 0; i < string.length(); i++) {
threadPoolExecutor.execute(new PrintRunnable(string, i));
} // 3秒后线程池调用shutdownNow设置线程中的interrupt中断标志位
TimeUnit.SECONDS.sleep(3);
System.out.printf("ThreadName: (%s) Preparing call shutdownNow()...\n", Thread.currentThread().getName());
threadPoolExecutor.shutdownNow(); }
}
这里通过guava包中ThreadFactoryBuilder设置线程池中的线程名;
提交string.length()个不同的线程任务(通过下标i打印不同的字符)到线程池中;
3秒后,主线程调用shutdownNow,这里主要是为了将正在运行的线程设置中断标志位,死循环利用中断标志位结束循环,或线程调用了等待方法(如wait)会抛出异常InterruptException未被捕获而停止。
shutdownNow 方法:此方法执行后不得向线程池再提交任务,如果有空闲线程则销毁空闲线程,取消所有位于阻塞队列中的任务,并将其放入 List容器,作为返回值;取消正在执行的线程(实际上仅仅是设置正在执行线程的中断标志位,调用线程的 interrupt 方法来中断线程)。
启动main方法,多个线程按顺序打印"abcdefg",3s后结束,执行结果部分截图如下:
当然也可以通过另一种"等待-唤醒"机制实现,如用一个ReentrantLock对象的的newCondition()方法创建多个Condition对象,再利用Condition对象的await()搭配signal()或signalAll();
也可利用取余运算%判断线程需要打印的字符,不用生成多个 Condition对象,可利用一个Condition对象,而且可以改变,随便多少个线程打印多少个字符。
JAVA线程状态、线程START方法源码、多线程、JAVA线程池、如何停止一个线程
多个线程分别顺序交替打印一种不同字符abcdefg(已实现随便多少个线程打印多少个字符,利用线程池实现多线程)的更多相关文章
- 多线程面试题之【三线程按顺序交替打印ABC的方法】
建立三个线程,线程名字分别为:A.B.C,要求三个线程分别打印自己的线程名字,但是要求三个线程同时运行,并且实现交替打印,即按照ABCABCABC的顺序打印.打印10轮,打印完毕控制台输出字符串:&q ...
- 三个线程ABC,交替打印ABC
转载与:https://www.cnblogs.com/x_wukong/p/4009709.html 创建3个线程,让其交替打印ABC . 输出如下: ABCABCABCABC. 方法:使用syn ...
- 用三个线程按顺序循环打印ABC三个字母
有两种方法:semaphore信号量和mutex互斥锁.需要注意的是C++11已经没有semaphore. C++ 并发编程(六):信号量(Semaphore) - 止于至善 - SegmentFau ...
- 三个线程T1,T2,T3.保证顺序执行的三种方法
经常看见面试题:有三个线程T1,T2,T3,有什么方法可以确保它们按顺序执行.今天手写测试了一下,下面贴出目前想到的3种实现方式 说明:这里在线程中我都用到了sleep方法,目的是更容易发现问题.之前 ...
- C#之使用AutoResetEvent实现线程的顺序执行
前几天一朋友问我如何实现线程的顺序执行,说真的,虽然看过CLR这本书,也把线程部分拜读了两遍,但是这个问题出来之后还是没有一个思路.今天在搜索资料的时候无意中再次看到AutoResetEvent这个东 ...
- Qt 控制线程的顺序执行(使用QWaitCondition,并且线程类的run函数里记得加exec(),使得线程常驻)
背景项目中用到多线程,对线程的执行顺序有要求: A.一个线程先收数据 B.一个线程处理数据 C.一个线程再将处理后的数据发送出去 要求三个线程按照ABC的顺序循环执行. 思路子类化多线程方法 重写子类 ...
- 【Java多线程系列四】控制线程执行顺序
假设有线程1/线程2/线程3,线程3必须在线程1/线程2执行完成之后开始执行,有两种方式可实现 Thread类的join方法:使宿主线程阻塞指定时间或者直到寄生线程执行完毕 CountDownLatc ...
- 实现线程按顺序输出ABC
线程按顺序输出ABC 实现描述:建立三个线程A.B.C,分别按照顺序输出十次ABC 首先建立一个方法,按照条件进行输出 class PrintABC{ private int index=0; pub ...
- Java之CountDownLatch ---控制线程执行顺序
一,类介绍 这是java.util.concurrent包里的一个同步辅助类,它有两个主要的常用方法 countDown()方法以及await()方法.在完成一组正在其他线程中执行的操作之前,它允许 ...
随机推荐
- vue-cli入门 - 搭建项目打包运行+webpack打包
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/qq_38225558/article/d ...
- c# .net 4.5.2 asp.net mvc 使用hangfire
一定要有hangfire数据库,否则hangfire会报错. (obStorage.Current property value has not been initialized. You must ...
- Java序列化的方式。
0.前言 本文主要对几种常见Java序列化方式进行实现.包括Java原生以流的方法进行的序列化.Json序列化.FastJson序列化.Protobuff序列化. 1.Java原生序列化 Java原生 ...
- c++11多线程记录5: Unique Lock和延时初始化
https://www.youtube.com/user/BoQianTheProgrammer 视频网址 Unique Lock unique_lock和lock_guard类似,都是mutex的w ...
- 下载并使用MNIST数据集
TensorFlow提供了一个库,可以直接用来自动下载与安装MNIST. MNIST里包含3个数据集:第一个是训练数据集(mnist.train.images),另外两个分别是测试数据集(mnist. ...
- Python 基础 while 循环
Python 基础 while 循环 while 循环 在生活中,我们遇到过循环的事情吧?比如循环听歌.在程序中,也是存才的,这就是流程控制语句 while 基本循环 while 条件: # 循环体 ...
- robotframework_接口自动化
我们在使用rebotframework的时候,不只是能做UI自动化,接口自动化也是可以的. 那么这里就整理一下rebotframework_接口自动化的应用: 一.编写接口测试 由上图可知,该接口如下 ...
- 魔法 [线段树优化DP]
也许更好的阅读体验 \(\mathcal{Description}\) 小 \(D\) 正在研究魔法. 小 \(D\) 得到了远古时期的魔法咒语 \(S\),这个咒语共有 \(n\) 个音节,每个音节 ...
- Angular—入门环境,项目创建,导入项目
1.安装 nodejs,npm nodejs 下载地址: https://nodejs.org/en/download/
- go install -v github.com/gopherjs/gopherjs报错提示go cannot find package "golang.org/x/crypto/ssh/terminal" 解决方案
1前言 方法一:go get 方法二: github clone 2 方法方法一:go get go get golang.org/x/crypto/ssh/terminal 但是这种方法容易被墙,出 ...