多线程按序轮流输出为什么能保持顺序和为什么越界?

kathy_koo 2020-08-12 02:39:58

class PingPong3 extends Thread{
public static void main(){
AtomicInteger i = new AtomicInteger(0);
int end = 40;
int total = 5;
for(int k=0; k<total; k++) {
new PingPong3("t"+(k+1), i, k, total, end).start();
}
}
AtomicInteger i;
int end;
int total;
int order;
String name;
PingPong3(String name, AtomicInteger i, int order, int total, int end){
this.name = name;
this.order = order;
this.i = i;
this.end = end;
this.total = total;
}
@Override
public void run() {//会越界打印出40和41
while (i.get() < end) {
synchronized(i){
if (i.get() % total == order) {
System.out.println(name + ":" + i.getAndIncrement());
}
}
}
System.out.println(name+": exit");
}
}


这是一段多线程按顺序轮流输出一串数字的程序
原帖 https://bbs.csdn.net/topics/397406694

icoolno1 网友给出这个版本的代码
这段代码的实际效果如下

t1:0
t2:1
t3:2
t4:3
t5:4
t1:5
t2:6
t3:7
t4:8
t5:9
t1:10
t2:11
t3:12
t4:13
t5:14
t1:15
t2:16
t3:17
t4:18
t5:19
t1:20
t2:21
t3:22
t4:23
t5:24
t1:25
t2:26
t3:27
t4:28
t5:29
t1:30
t2:31
t3:32
t4:33
t5:34
t1:35
t2:36
t3:37
t4:38
t5:39
t1:40
t4: exit
t2:41
t5: exit
t1: exit
t2: exit
t3:42
t3: exit


即这段代码确实可以按顺序输出,并且可以正常退出,唯一不正常的是线程可能会发生一次越界,无法及时退出

我对这个版本的代码有几点无法理解
1. 为什么能给按顺序输出
2. 为什么会发生越界
...全文
408 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq_39936465 2020-08-12
  • 打赏
  • 举报
回复
引用 楼主 kathy_koo 的回复:
即这段代码确实可以按顺序输出,并且可以正常退出,唯一不正常的是线程可能会发生一次越界,无法及时退出 我对这个版本的代码有几点无法理解 1. 为什么能给按顺序输出 2. 为什么会发生越界
原因很简单,因为不越界的话,程序继续在循环,你看不出问题。当i=39时的,其实5个线程不管谁取得锁都是得到i=39,这时候只有t5才会输出内容并i+1,t5回到while判断等于end,所以t5不再循环直接结束。而其他4个程序会随机获得锁,这时候只要不是t0的线程获得锁,因为不满足条件会回到while进行判断等于end而退出程序。这时候最极端的情况是t0在4个线程最后一个获得锁,这时候因为不会判断i是否越界,还是满足i.get() % total == order的条件输出i的值,后才会回到while判断退出。如果余下线程获取锁都是按正常次序的话就有可能4次越界。所以他的程序最少1次最多会4次越界。
丿Mars丨巛恋 2020-08-12
  • 打赏
  • 举报
回复
程序运行话占用cpu,而cpu是有限的,线程是具有抢占性的,所以cpu会分成时间片,而一个主函数中含有线程时,会有多个线程共同去抢占时间片,但是时间片是有限的,抢到后不一定能执行完,便会被其他线程抢占,执行相关的程序
timi先生 2020-08-12
  • 打赏
  • 举报
回复
线程进入标记为 synchronized 的代码块时,Java 会立即锁定 synchronized 一词后面括号内指示的对象的互斥锁。在此线程离开之前,没有其他线程可以进入此代码块。一旦此线程离开标记为 synchronized 的代码块,互斥锁将立即自动解锁,并可被另一个线程获取。 这个程序中 i 被指定为对象的互斥锁,所以线程的进行不再是同步的,先抢到 i的线程运行时,其他线程处于堵塞状态。
大隐藏于寺 2020-08-12
  • 打赏
  • 举报
回复
执行流程如下 1.while循环条件判断,如果当前i小于end,继续执行方法体; 2. 遇到synchronized代码块,在执行前当前线程一定要获取到锁,如果没有获取到锁当前线程进入Waiting状态,直到获取到锁,如果获取到锁就执行同步代码块中的代码,在执行完后会自动释放锁. 3.回到1,继续进行while循环条件判断. 发生越界的原因在你之前那个帖子已经说明了.这里再说一下,某个线程A在获取到锁之前,已经进行了while循环的判断,此时i的确是小于end的,但是线程A获取到锁后,此时的i可能已经被其它线程修改过,但是在获取到锁后并没有进行再次判断,就造成了输出的数字超过end.

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧