下面实现多线程顺序打印字符"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(已实现随便多少个线程打印多少个字符,利用线程池实现多线程)的更多相关文章

  1. 多线程面试题之【三线程按顺序交替打印ABC的方法】

    建立三个线程,线程名字分别为:A.B.C,要求三个线程分别打印自己的线程名字,但是要求三个线程同时运行,并且实现交替打印,即按照ABCABCABC的顺序打印.打印10轮,打印完毕控制台输出字符串:&q ...

  2. 三个线程ABC,交替打印ABC

    转载与:https://www.cnblogs.com/x_wukong/p/4009709.html 创建3个线程,让其交替打印ABC . 输出如下:  ABCABCABCABC. 方法:使用syn ...

  3. 用三个线程按顺序循环打印ABC三个字母

    有两种方法:semaphore信号量和mutex互斥锁.需要注意的是C++11已经没有semaphore. C++ 并发编程(六):信号量(Semaphore) - 止于至善 - SegmentFau ...

  4. 三个线程T1,T2,T3.保证顺序执行的三种方法

    经常看见面试题:有三个线程T1,T2,T3,有什么方法可以确保它们按顺序执行.今天手写测试了一下,下面贴出目前想到的3种实现方式 说明:这里在线程中我都用到了sleep方法,目的是更容易发现问题.之前 ...

  5. C#之使用AutoResetEvent实现线程的顺序执行

    前几天一朋友问我如何实现线程的顺序执行,说真的,虽然看过CLR这本书,也把线程部分拜读了两遍,但是这个问题出来之后还是没有一个思路.今天在搜索资料的时候无意中再次看到AutoResetEvent这个东 ...

  6. Qt 控制线程的顺序执行(使用QWaitCondition,并且线程类的run函数里记得加exec(),使得线程常驻)

    背景项目中用到多线程,对线程的执行顺序有要求: A.一个线程先收数据 B.一个线程处理数据 C.一个线程再将处理后的数据发送出去 要求三个线程按照ABC的顺序循环执行. 思路子类化多线程方法 重写子类 ...

  7. 【Java多线程系列四】控制线程执行顺序

    假设有线程1/线程2/线程3,线程3必须在线程1/线程2执行完成之后开始执行,有两种方式可实现 Thread类的join方法:使宿主线程阻塞指定时间或者直到寄生线程执行完毕 CountDownLatc ...

  8. 实现线程按顺序输出ABC

    线程按顺序输出ABC 实现描述:建立三个线程A.B.C,分别按照顺序输出十次ABC 首先建立一个方法,按照条件进行输出 class PrintABC{ private int index=0; pub ...

  9. Java之CountDownLatch ---控制线程执行顺序

    一,类介绍 这是java.util.concurrent包里的一个同步辅助类,它有两个主要的常用方法  countDown()方法以及await()方法.在完成一组正在其他线程中执行的操作之前,它允许 ...

随机推荐

  1. 启动Oracle 12c数据库实例

    启动Oracle 12c数据库实例 启动Oracle数据库实例,主要分为两步:第一步,启动监听:第二步,启动数据库实例. 1. 切换到oracle用户- su oracle- cd - source ...

  2. Vue 搭建项目

    Vue  搭建项目 一.node下载安装: 1.下载:https://nodejs.org/en/download/ 2.安装默认许选择,下一步就行: 3.安装完之后就可以使用npm命令 二.通过@v ...

  3. 百度AI身份证识别demo,使用js提交图片数据

    <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...

  4. ES6学习小结

    ES6(ES2015)--IE10+.Chrome.FireFox.移动端.NodeJS 编译.转换 1.在线转换 2.提前编译 babel = browser.js ES6: 1.变量 var 重复 ...

  5. “无法从节点xx检索exectask的版本” 原因分析

    客户有一套部署在Window 2008 R2 sp环境下的12.1.0.2 RAC环境,该RAC基于策略管理.因为业务需要,现在需要更换部分设备——踢出两台2路的服务器(节点名称分别为racnode2 ...

  6. Navicat 创建oracle表空间、新建用户、授权

    1.利用数据库管理员账号:SYSTEM,再配合数据库管理口令,连接Oracle数据库. 登录界面: 2.创建表空间文件 进入如下界面 进入如下界面 弹出如下界面,输入表空间名称 最终结果:  2 .新 ...

  7. vue 在发送axios请求时数据渲染问题

    这是我请求的json格式的数据 一开始在vue用普通的数据渲染,更改为vue后使用v-for 发现没办法渲染上去了. obj.data就是以上数据. 必须加上这三行给this随意赋个值,神奇的事情就会 ...

  8. 【实战经验】--Xilinx--IPcore--MCB(DDR3)运用

    1.背景与介绍 1)在导师安排的新的任务中,用到了一块2G大小的DDR3(MT41K128M16JT-107).本打算像之前用SDRAM一样自己写初始化,读写模块,但是师兄跟我说可以用Xilinx自带 ...

  9. sqlserver通过递归查找所有下级或上级部门和用户的操作实例

    --查找当前用户所在部门的所有下级包括当前部门 with cte as ( as lvl from Department union all from cte c inner join Departm ...

  10. C#泛型集合之——链表

    链表基础 1.概述:C#中泛型集合中的链表—LinkedList 是一个双向链表,其结点为LinkedListNode 结构 其中,结点结构包含:Next,Previous,Value三部分.且结点中 ...