在用多线程去测试race condition的时候,出现了前后输出但总次数大小不一的情况,最关键大小不是增序而是无序。求大神解答!谢谢!
package ThreadTry;
import java.util.Scanner;
/**
* Created by Administrator on 2019/5/2 0002.
*/
public class Homework {
public static void main(String args[]) throws InterruptedException {
Th th1,th2,th3,th4,th5;
System.out.println("请设定每个线程的睡眠时间(ms):");
Scanner reader=new Scanner(System.in);
int t=reader.nextInt();
Th.setTime(t);
Th th=new Th();
Thread thread1,thread2,thread3,thread4,thread5,thread6,thread7,thread8,thread9,thread10;
thread1=new Thread(th);
thread1.setName("线程1");
thread2=new Thread(th);
thread2.setName("线程2");
thread3=new Thread(th);
thread3.setName("线程3");
thread4=new Thread(th);
thread4.setName("线程4");
thread5=new Thread(th);
thread5.setName("线程5");
thread6=new Thread(th);
thread6.setName("线程6");
thread7=new Thread(th);
thread7.setName("线程7");
thread8=new Thread(th);
thread8.setName("线程8");
thread9=new Thread(th);
thread9.setName("线程9");
thread10=new Thread(th);
thread10.setName("线程10");
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
thread6.start();
thread7.start();
thread8.start();
thread9.start();
thread10.start();
thread1.join();
thread2.join();
thread3.join();
thread4.join();
thread5.join();
thread6.join();
thread7.join();
thread8.join();
thread9.join();
thread10.join();
System.out.println("次数="+th.getCounters());
}
}
class Th implements Runnable {
int counter = 0;
static int t = 0;
static void setTime(int x) {
t = x;
}
@Override
public void run() {
String name=Thread.currentThread().getName();
for (int i = 0; i < 1000; i++) {
counter++;
try {
Thread.sleep(t);
}
catch (InterruptedException e) {
}
}
System.out.println("我是"+name+"次数="+counter);
}
int getCounters(){
return counter;
}
}
这个是输出结果:
counter是成员变量,这意味着它是在线程之间共享的,所以需要同步。
counter++不是原子操作。
它实际上存在3个步骤
a 把counter当前的值读取到cpu的寄存器
b cpu对它+1
c 然后将结果写回counter
如果第一个线程完成了a步骤,然后被挂起,此时执行第二个线程,并且完成了abc三个步骤,此时counter被+1,然后线程1继续执行,此时cpu里面的值还是没有+1之前的值。
它+1后也写回,按理说,应该再+1,但是实际上因为它是在没有+1的情况下+1,所以只加了一个1。运行很多次,当这个情况出现了很多次,最后的结果就少了一些。
每个线程每次循环后都有一个sleep(0)操作,导致任务重新调度,最后一次循环后,打印前也一定会进行一次任务重调度,什么时候能回来接着打印就不确定了;那就有可能出现先循环完的结果却后打印出来,表现出来的就是后打印的数字比先打印的数字小。
再看counter本身对各个线程是个全局的,而++非原子操作,可能导致counter被覆盖的情况,表现出来的就是执行了10000次++,结果总数却只加到了9879