java 多线程顺序打印_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 TestSequential01 {

private volatile int pos = 1;

private volatile int count = 0;

private final Object obj = new Object();

public void run(int i) {

int next = i % 3 + 1;

while(true) {

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 = next;

count = 0;

obj.notifyAll();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

public static void main(String[] args) {

TestSequential01 demo = new TestSequential01();

for (int i = 3; i >=1; i--) {

int j = i;

new Thread(()->{

demo.run(j);

}).start();

}

}

}

输出

3 in

3 wait

1 in

T-1 1

1 in

1 wait

2 in

T-2 1

2 in

2 wait

1 wait

T-3 2

3 in

3 wait

T-1 1

1 in

1 wait

T-2 1

2 in

2 wait

1 wait

T-3 2

3 in

3 wait

T-1 1

1 in

1 wait

方法三: 使用可重入锁

用Lock做, 非公平锁, 三个线程竞争, 如果遇上的是自己的数字, 就打印. 这种方式会浪费大量的循环

public class TestSequential01 {

private final Lock lock = new ReentrantLock();

private volatile int pos = 1;

private volatile int count = 0;

public void run(int i) {

int next = i % 3 + 1;

while(true) {

lock.lock();

if (pos == i) {

System.out.println("T-" + i + " " + count);

pos = next;

count = 0;

} else {

count++;

}

lock.unlock();

}

}

public static void main(String[] args) {

TestSequential01 demo = new TestSequential01();

for (int i = 1; i <=3; i++) {

int j = i;

new Thread(()->{

demo.run(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

给每个线程不同的condition. 可以用condition.signal()精确地通知对应的线程继续执行(在对应的condition上await的线程, 可能是多个).

public class TestSequential01 {

private static Lock lock = new ReentrantLock();

private static Condition[] conditions = {lock.newCondition(), lock.newCondition(), lock.newCondition()};

private volatile int state = 1;

private void run(final int self) {

int next = self % 3 + 1;

while(true) {

lock.lock();

try {

while(this.state != self) {

conditions[self - 1].await();

}

System.out.println(self);

this.state = next;

conditions[next - 1].signal();

} catch (InterruptedException e) {

e.printStackTrace();

}

lock.unlock();

}

}

public static void main(String[] args) {

TestSequential01 rlc = new TestSequential01();

for (int i = 1; i < 4; i++) {

int j = i;

new Thread(()->rlc.run(j)).start();

}

}

}

总结

在使用wait()和await()的竞争环境, 因为被notifyAll()和signal()之后到线程回到执行之前, 条件可能发生变化, 所以必须在wait()和await()外包使用while循环检测条件, 这是一个通用方法

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值