为什么每个线程输出的counter大小不一,先输出的可能比后输出的要大?

在用多线程去测试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;
    }
}

这个是输出结果:
图片说明

2个回答

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

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐