Java多个线程顺序打印数字
要求
启动N个线程, 这N个线程要不间断按顺序打印数字1-N. 将问题简化为3个线程无限循环打印1到3
方法一: 使用synchronized
三个线程无序竞争同步锁, 如果遇上的是自己的数字, 就打印. 这种方式会浪费大量的循环
- public class TestSequential1 {
- private volatile int pos = 1;
- private volatile int count = 0;
- public void one(int i) {
- synchronized (this) {
- if (pos == i) {
- System.out.println("T-" + i + " " + count);
- pos = i % 3 + 1;
- count = 0;
- } else {
- count++;
- }
- }
- }
- public static void main(String[] args) {
- TestSequential1 demo = new TestSequential1();
- for (int i = 1; i <=3; i++) {
- int j = i;
- new Thread(()->{
- while(true) {
- demo.one(j);
- }
- }).start();
- }
- }
- }
输出
- T-1 0
- T-2 5793
- T-3 5285
- T-1 2616
- T-2 33
- T-3 28
- T-1 22
- T-2 44
- T-3 6
- T-1 881
- T-2 118358
- T-3 247380
- T-1 30803
- T-2 29627
- T-3 52044
- ...
方法二: 使用synchronized配合wait()和notifyAll()
竞争同步锁时使用wait()和notifyAll(), 可以避免浪费循环
- public class TestSequential4 {
- private volatile int pos = 1;
- private volatile int count = 0;
- private final Object obj = new Object();
- public void one(int i) {
- System.out.println(i + " try");
- synchronized (obj) {
- System.out.println(i + " in");
- try {
- while (pos != i) {
- count++;
- System.out.println(i + " wait");
- obj.wait();
- }
- System.out.println("T-" + i + " " + count);
- pos = i % 3 + 1;
- count = 0;
- obj.notifyAll();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- public static void main(String[] args) {
- TestSequential4 demo = new TestSequential4();
- for (int i = 3; i >=1; i--) {
- int j = i;
- new Thread(()->{
- while(true) {
- demo.one(j);
- }
- }).start();
- }
- }
- }
输出
- 3 try
- 3 in
- 3 wait
- 2 try
- 2 in
- 2 wait
- 1 try
- 1 in
- T-1 2
- 1 try
- 1 in
- 1 wait
- T-2 1
- 2 try
- 2 in
- 2 wait
- T-3 1
- 3 try
- 3 in
- 3 wait
- 2 wait
- T-1 2
- 1 try
- 1 in
- 1 wait
- T-2 1
- 2 try
- 2 in
- 2 wait
- T-3 1
- 3 try
- 3 in
- 3 wait
- 2 wait
- T-1 2
- 1 try
- 1 in
- 1 wait
- T-2 1
- 2 try
- 2 in
- 2 wait
- T-3 1
- 3 try
- 3 in
- 3 wait
- 2 wait
- T-1 2
- 1 try
- 1 in
- 1 wait
- T-2 1
- 2 try
- 2 in
- 2 wait
- T-3 1
- 3 try
- 3 in
- 3 wait
- 2 wait
- T-1 2
- 1 try
- 1 in
- 1 wait
- T-2 1
- 2 try
- 2 in
- 2 wait
- T-3 1
- 3 try
- 3 in
- 3 wait
- 2 wait
- T-1 2
- 1 try
- 1 in
- 1 wait
- T-2 1
- 2 try
- 2 in
- 2 wait
- T-3 1
- 3 try
- 3 in
- 3 wait
- 2 wait
- T-1 2
- 1 try
- 1 in
- 1 wait
- T-2 1
- 2 try
- 2 in
- 2 wait
- T-3 1
- 3 try
- 3 in
- 3 wait
- 2 wait
- T-1 2
- 1 try
- 1 in
- 1 wait
- T-2 1
- 2 try
- 2 in
- 2 wait
- T-3 1
- 3 try
- 3 in
- 3 wait
- 2 wait
- T-1 2
- 1 try
- 1 in
- 1 wait
- T-2 1
- 2 try
- 2 in
- 2 wait
- T-3 1
- 3 try
- 3 in
- 3 wait
- 2 wait
- T-1 2
- ...
.
方法三: 使用可重入锁
用Lock做, 非公平锁, 三个线程竞争, 如果遇上的是自己的数字, 就打印. 这种方式也会浪费大量的循环
- public class TestSequential2 {
- private final Lock lock = new ReentrantLock();
- private volatile int pos = 1;
- private volatile int count = 0;
- public void one(int i) {
- lock.lock();
- if (pos == i) {
- System.out.println("T-" + i + " " + count);
- pos = i % 3 + 1;
- count = 0;
- } else {
- count++;
- }
- lock.unlock();
- }
- public static void main(String[] args) {
- TestSequential2 demo = new TestSequential2();
- for (int i = 1; i <=3; i++) {
- int j = i;
- new Thread(()->{
- while(true) {
- demo.one(j);
- }
- }).start();
- }
- }
- }
输出
- T-1 0
- T-2 0
- T-3 323
- T-1 54
- T-2 68964
- T-3 97642
- T-1 6504
- T-2 100603
- T-3 6989
- T-1 1313
- T-2 0
- T-3 183741
- T-1 233
- T-2 5081
- T-3 164367
- ..
.
方法四: 使用可重入锁, 启用公平锁
和3一样, 但是使用公平锁, 这种情况下基本上可以做到顺序执行, 偶尔会产生多一次循环
- private final Lock lock = new ReentrantLock(true);
输出
- T-1 0
- T-2 0
- T-3 0
- T-1 0
- T-2 0
- T-3 0
- T-1 0
- T-2 0
- T-3 0
- T-1 0
- T-2 0
- T-3 1
- T-1 1
- T-2 1
- T-3 1
- ...
.
方法五: 使用Condition
每个线程如果看到不是自己的计数, 就await(), 如果是自己的计数, 就完成打印动作, 再signalAll()所有其他线程去继续运行, 自己在下一个循环后, 即使又继续执行, 也会因为计数已经变了而await.
如果ReentrantLock构造参数使用true, 可以基本消除 ~await 这一步的输出.
- public class ReentrantLockCondition2 {
- private static Lock lock = new ReentrantLock();
- private static Condition condition = lock.newCondition();
- private volatile int state = 1;
- private void handle(int state) {
- lock.lock();
- try {
- while(true) {
- while(this.state != state) {
- System.out.println(state + " ~await");
- condition.await();
- }
- System.out.println(state);
- this.state = state % 3 + 1;
- condition.signalAll();
- System.out.println(state + " await");
- condition.await();
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- } finally {
- lock.unlock();
- }
- }
- public static void main(String[] args) {
- ReentrantLockCondition2 rlc = new ReentrantLockCondition2();
- new Thread(()->rlc.handle(1)).start();
- new Thread(()->rlc.handle(2)).start();
- new Thread(()->rlc.handle(3)).start();
- }
- }
.
方法六: 使用多个Condition
给每个线程不同的condition. 这个和4的区别是, 可以用condition.signal()精确地通知对应的线程继续执行(在对应的condition上await的线程, 可能是多个). 这种情况下是可以多个线程都不unlock锁的情况下进行协作的. 注意下面的while(true)循环是在lock.lock()方法内部的.
- public class ReentrantLockCondition {
- private static Lock lock = new ReentrantLock();
- private static Condition[] conditions = {lock.newCondition(), lock.newCondition(), lock.newCondition()};
- private volatile int state = 1;
- private void handle(int state) {
- lock.lock();
- try {
- while(true) {
- while(this.state != state) {
- conditions[state - 1].await();
- }
- System.out.println(state);
- this.state = state % 3 + 1;
- conditions[this.state - 1].signal();
- conditions[state - 1].await();
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- } finally {
- lock.unlock();
- }
- }
- public static void main(String[] args) {
- ReentrantLockCondition rlc = new ReentrantLockCondition();
- new Thread(()->rlc.handle(1)).start();
- new Thread(()->rlc.handle(2)).start();
- new Thread(()->rlc.handle(3)).start();
- }
- }
.
Java多个线程顺序打印数字的更多相关文章
- Java n个线程轮流打印数字的问题
一. 实现两个线程.轮流打印出数字.例如以下: bThread --> 10 aThread --> 9 bThread --> 8 aThread --> 7 bThread ...
- java启动3个线程轮流打印数字
转自:http://blog.csdn.net/u014011112/article/details/50988769 http://blog.csdn.net/perrywork/article/d ...
- 【多线程基础】- 多个线程顺序打印ABC
题目:3个线程名字分别是A,B,C 现在在console上连续打印10次 ABC . public class Test { public static void main(String[] args ...
- Linux 多线程按照线程顺序打印字符
#include <stdio.h> #include <pthread.h> #include <unistd.h> ; pthread_mutex_t mute ...
- java面试记录二:spring加载流程、springmvc请求流程、spring事务失效、synchronized和volatile、JMM和JVM模型、二分查找的实现、垃圾收集器、控制台顺序打印ABC的三种线程实现
注:部分答案引用网络文章 简答题 1.Spring项目启动后的加载流程 (1)使用spring框架的web项目,在tomcat下,是根据web.xml来启动的.web.xml中负责配置启动spring ...
- 使用Java实现三个线程交替打印0-74
使用Java实现三个线程交替打印0-74 题目分析 三个线程交替打印,即3个线程是按顺序执行的.一个线程执行完之后,唤醒下一个线程,然后阻塞,等待被该线程的上一个线程唤醒.执行的顺序是一个环装的队列 ...
- 使用Java线程并发库实现两个线程交替打印的线程题
背景:是这样的今天在地铁上浏览了以下网页,看到网上一朋友问了一个多线程的问题.晚上闲着没事就决定把它实现出来. 题目: 1.开启两个线程,一个线程打印A-Z,两一个线程打印1-52的数据. 2.实现交 ...
- Java中如何保证线程顺序执行
只要了解过多线程,我们就知道线程开始的顺序跟执行的顺序是不一样的.如果只是创建三个线程然后执行,最后的执行顺序是不可预期的.这是因为在创建完线程之后,线程执行的开始时间取决于CPU何时分配时间片,线程 ...
- Java线程同步打印ABC
需求: 三个线程,依次打印ABCABCABC.... 方案一: 使用阻塞队列,线程1从队列1获取内容打印,线程2从队列2获取内容打印,线程3从队列3中获取内容打印.线程1把B放到队列3中,线程2把C放 ...
随机推荐
- JavaScript: 详解正则表达式之一
正则表达式是一个精巧的利器,经常用来在字符串中查找和替换,JavaScript语言参照Perl,也提供了正则表达式相关模块,开发当中非常实用,在一些类库或是框架中,比如jQuery,就存在大量的正则表 ...
- Linux之RHEL7root密码破解(二)
破解Linux root密码的第二种方法,如下: 首先开机,进入启动界面,接着找到如下图所示的代码字段,将ro改成rw init=/sysroot/bin/sh ,如下图: 之后按“Ctrl+X”之后 ...
- 一些替代Xshell的软件推荐
FinalShell: 面附上一些截图和官方连接: 官网:http://www.hostbuf.com/ FinalShell是一体化的的服务器,网络管理软件,不仅是ssh客户端,还是功能强大的开发, ...
- django项目中使用手机号登录
本文使用聚合数据的短信接口,需要先获取到申请接口的appkey和模板id 项目目录下创建ubtils文件夹,定义返回随机验证码和调取短信接口的函数 function.py文件 import rando ...
- Good Numbers(HDU5447+唯一分解)
题目链接 传送门 题面 题意 首先定义对于\(k\)的好数\(u\):如果\(u\leq k\)且\(u\)的所有质因子与\(k\)的质因子一样则称\(u\)对于\(k\)是一个好数. 现给你两个数\ ...
- JavaWeb报错:java.sql.SQLException: Invalid value for getInt()
1.错误描述:在对数据库进行操作时,控制台报错:java.sql.SQLException: Invalid value for getInt() :2.错误原因:数据库中表的字段的类型与实体类中属性 ...
- 前端知识--控制input按钮的显示与隐藏
if(fm.ReadFlag.value=="readonly"){ var arr = document.getElementsByTagName("input&quo ...
- volatile 关键词
volatile 关键字指示一个字段可以由多个同时执行的线程修改. 出于性能原因,编译器,运行时系统甚至硬件都可能重新排列对存储器位置的读取和写入. 声明了 volatile 的字段不进行这些优化.这 ...
- window对象(全局对象)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 004——转载—Word2016“此功能看似已中断 并需要修复”问题解决办法
解决办法如下: 在Win10系统上安装 Office 2016 之后,每次打开Word文档可能都会提示“很抱歉,此功能看似已中断,并需要修复,请使用Windows 控制面板中的“程序和功能”选项修复M ...