要求

启动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多个线程顺序打印数字的更多相关文章

  1. Java n个线程轮流打印数字的问题

    一. 实现两个线程.轮流打印出数字.例如以下: bThread --> 10 aThread --> 9 bThread --> 8 aThread --> 7 bThread ...

  2. java启动3个线程轮流打印数字

    转自:http://blog.csdn.net/u014011112/article/details/50988769 http://blog.csdn.net/perrywork/article/d ...

  3. 【多线程基础】- 多个线程顺序打印ABC

    题目:3个线程名字分别是A,B,C 现在在console上连续打印10次 ABC . public class Test { public static void main(String[] args ...

  4. Linux 多线程按照线程顺序打印字符

    #include <stdio.h> #include <pthread.h> #include <unistd.h> ; pthread_mutex_t mute ...

  5. java面试记录二:spring加载流程、springmvc请求流程、spring事务失效、synchronized和volatile、JMM和JVM模型、二分查找的实现、垃圾收集器、控制台顺序打印ABC的三种线程实现

    注:部分答案引用网络文章 简答题 1.Spring项目启动后的加载流程 (1)使用spring框架的web项目,在tomcat下,是根据web.xml来启动的.web.xml中负责配置启动spring ...

  6. 使用Java实现三个线程交替打印0-74

    使用Java实现三个线程交替打印0-74 题目分析 三个线程交替打印,即3个线程是按顺序执行的.一个线程执行完之后,唤醒下一个线程,然后阻塞,等待被该线程的上一个线程唤醒.执行的顺序是一个环装的队列 ...

  7. 使用Java线程并发库实现两个线程交替打印的线程题

    背景:是这样的今天在地铁上浏览了以下网页,看到网上一朋友问了一个多线程的问题.晚上闲着没事就决定把它实现出来. 题目: 1.开启两个线程,一个线程打印A-Z,两一个线程打印1-52的数据. 2.实现交 ...

  8. Java中如何保证线程顺序执行

    只要了解过多线程,我们就知道线程开始的顺序跟执行的顺序是不一样的.如果只是创建三个线程然后执行,最后的执行顺序是不可预期的.这是因为在创建完线程之后,线程执行的开始时间取决于CPU何时分配时间片,线程 ...

  9. Java线程同步打印ABC

    需求: 三个线程,依次打印ABCABCABC.... 方案一: 使用阻塞队列,线程1从队列1获取内容打印,线程2从队列2获取内容打印,线程3从队列3中获取内容打印.线程1把B放到队列3中,线程2把C放 ...

随机推荐

  1. Nginx proxy_set_header

    配置示例 server{ server_name aaa.com location /api { proxy_pass http://xxx.com/api; proxy_set_header Hos ...

  2. day 04作业

    目录 简述Python的五大数据类型的作用.定义方式.使用方法: 数字类型 字符串类型(str) 列表(list) 字典(dict) 布尔型(bool) 一行代码实现下述代码实现的功能: 写出两种交换 ...

  3. HTML+Css+JavaScript知识点汇总

    HTML 部分 HTML基础知识 1. HTML简介 HTML(Hypertext Markup Language),超文本标记语言,HTML利用各种标记来标识文档的结构以及标识超链接的信息.它是从S ...

  4. 【Audiophobia UVA - 10048 】【Floyd算法】

    题目大意:从a城市到b城市的路径中,尽可能让一路上的最大噪音最小. 题目思路:设d [ i ][ j ]表示 i 到 j 的最大噪音的最小值. 那么d [ i ][ j ] = min( d[ i ] ...

  5. Integer面试连环炮以及源码分析

    场景:   昨天有位朋友去面试,我问他面试问了哪些问题,其中问了Integer相关的问题,以下就是面试官问的问题,还有一些是我对此做了扩展. 问:两个new Integer 128相等吗? 答:不.因 ...

  6. linux命令 node常用

    //查看进程netstat -nlp //查找某一进程 netstat -nlp | grep node //后台挂起 nohup npm start &

  7. [TJOI2015]概率论——期望&&母函数

    题意 求一个含有 $n$ 个结点的有序二叉树的叶子节点的期望个数.($n \leq 10^9$) 分析 一堆推导..... 得 $ans = \frac{n(n+1)}{2(2n-1)}$ #incl ...

  8. lambda表达式格式以及应用场景?

    lambda表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数. add = lambda x, y : x+y print(add(1,2)) # 结果为3 应 ...

  9. L1731

    生日蛋糕 输入的东西,一个是蛋糕的体积,一个是蛋糕的层数, 简言之,我觉得这个就是两个dfs的状态. 一旦越过这两个就得return ,同时这两个东西也参与进去了dfs. 至于题目, 第一个要求是层数 ...

  10. 10.31-11.1Test(未完)

    10.31-11.1Test 题目 描述 做法 \(BSOJ5177\) 求在\(n\)个数里选\(K\)个的所有方案的异或和之和 按位讨论,组合数算 \(BSOJ5178\) 化简\(\displa ...