多个线程分别顺序交替打印一种不同字符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()方法.在完成一组正在其他线程中执行的操作之前,它允许 ...
随机推荐
- 最常见的Java面试题及答案汇总(四)
反射 57. 什么是反射? 反射主要是指程序可以访问.检测和修改它本身状态或行为的一种能力 Java反射: 在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能 ...
- 【Spring Cloud学习之三】负载均衡
环境 eclipse 4.7 jdk 1.8 Spring Boot 1.5.2 Spring Cloud 1.2 主流的负载均衡技术有nginx.LVS.HAproxy.F5,Spring Clou ...
- python数据分析2之numpy
源代码 # -*- coding: utf-8 -*- """ Spyder Editor This is a temporary script file. " ...
- C/C++配置
VScode 插件推荐与C/C++配置 https://www.cnblogs.com/harrypotterjackson/p/11432252.html 阅读目录 C++类 美化 git tab ...
- STL源码剖析——序列式容器#4 Stack & Queue
Stack stack是一种先进后出(First In Last Out,FILO)的数据结构,它只有一个出口,元素的新增.删除.最顶端访问都在该出口进行,没有其他位置和方法可以存取stack的元素. ...
- Linux新装系统简单指南
也许更好的阅读体验 换源 1. 备份原来的源 sudo cp /etc/apt/sources.list /etc/apt/sources_init.list 2.更换源 先用\(gedit\)打开文 ...
- C#关键字:访问修饰符
一.访问修饰符 访问修饰符有public.private.protected.internal和protected internal.它们是修饰在类型(类.接口.委托.结构和枚举)和类型成员(字段.属 ...
- eclipse中启动tomcat后, 无法访问localhost:8080
问题: 今天老师讲了Servlet路径问题, 做了个测试在eclipse中启动tomcat后,在浏览器地址栏输入 http://localhost8080无法访问, 提示404错误, 正常情况是可以访 ...
- Python进阶----SOCKET套接字基础, 客户端与服务端通信, 执行远端命令.
Python进阶----SOCKET套接字基础, 客户端与服务端通信, 执行远端命令. 一丶socket套接字 什么是socket套接字: 专业理解: socket是应用层与TCP/IP ...
- sql分页优化
索引优化 注意查询的数据占总数据达到一定量的时候可能导致索引失效.可以用limit或者指定列缩小数据区域可以解决. 以时间orderby排序的limit分页优化 前提用order by分页 limit ...