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放 ...
随机推荐
- Set,List,Map,Collection
// JAVA集合主要分为三种类型: // // Set(集) List(列表) Map(映射) Collection 接口 // // Collection是最基本的集合接口,声明了适用于JAVA集 ...
- An exception has occurred, use %tb to see the full traceback.----parser.parse_args()报错
一.报错: 原因: 由于在jupyter notebook中,args不为空. 二.问题解决 改成args = parser.parse_args(args=[])
- 基于appium快速实现H5自动化测试
一.下载Appium-Server及库文件 库文件:jar包:java-client-3.1.0.jar Appium-Server:Appium服务器: 注:Appium包含客户端和服务端,客户端就 ...
- python笔记35-装饰器
前言 python装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象. 很多python初学者学到面向对象类和方法是一道大坎,那么p ...
- libpng 漏洞分析
相关资源 PNG文件格式文档 http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html https://www.myway5.com/index.p ...
- 10、Python迭代器与生成器(iterator、for循环、generator、yield)
一.迭代器(foreach) 1.可迭代的对象 内置有__iter__方法的都叫可迭代的对象. Python内置str.list.tuple.dict.set.file都是可迭代对象. x = 1._ ...
- Fiddler抓包工具使用指南|手机安装Fiddler的安全证书
Fiddler 4 1.设置: Tools -> Telerik Fiddler Options 勾选远程 手机安装证书 ->使用Android手机的浏览器打开:http://10.2. ...
- C# 跨线程对控件赋值
第一种 跨线程对控件赋值 private void button2_Click(object sender, EventArgs e) { Thread thread1 = new Thread(ne ...
- 算法笔记求序列A每个元素左边比它小的数的个数(树状数组和离散化)
#include <iostream> #include <algorithm> #include <cstring> using namespace std ; ...
- 完美兼容IE10以下所有版本
IE一直是个恶心东西 各种不支持 现在发现了个好东西可以兼容ie10以下所有浏览器 <!--[if lte IE 9]><script>window.location.href ...