Java中竞态条件和使用synchronized关键字同步

首先举一个例子:
定义一个 CountThread 类,如下,在 run 函数中进行全局变量的自增操作。

public class CountThread extends Thread{

    private int count = 0;

    @Override
    public void run() {
        count++;
        System.out.println(Thread.currentThread().getName() + " - " + count);
    }

}

调用的测试类如下:

public class Run {

    public static void main(String[] args) throws InterruptedException{
        CountThread countThread = new CountThread();
        for(int i=0; i<1000; i++){
            Thread thread = new Thread(countThread);
            thread.start();
        }
    }

}

运行结果如下(截取部分):

Thread-1 - 1
Thread-2 - 3
Thread-3 - 2
Thread-4 - 4
Thread-5 - 5
Thread-8 - 6
Thread-7 - 7
Thread-11 - 8
Thread-17 - 12
Thread-21 - 13
Thread-15 - 14
Thread-23 - 16
Thread-10 - 17
Thread-14 - 18
Thread-18 - 20
Thread-19 - 20
...
Thread-980 - 978
Thread-981 - 979
Thread-983 - 981
Thread-982 - 981
Thread-984 - 982
Thread-986 - 984
Thread-985 - 984
Thread-989 - 985
Thread-987 - 986
Thread-990 - 987
Thread-991 - 988
Thread-993 - 989
Thread-994 - 990
Thread-995 - 992
Thread-992 - 993
Thread-988 - 991
Thread-996 - 994
Thread-997 - 995
Thread-999 - 997
Thread-998 - 996
Thread-1000 - 998

根据截取的部分可以看到某些线程,执行 count++ 后输出了同样的结果,比如 Thread-18 和 Thread-19,二者均输出 20。同样还有 Thread-985 和 Thread-986,二者均输出 984。造成这个问题的原因就是自增操作并不是原子性的,自增的方法要分为如下的三步来执行:

一.将 count 的值读入寄存器中;
二.将 count1;
三.将 count 保存回内存中。

如果A线程在执行完第一步后,CPU交给B线程来执行,B线程也将 count 的值读入寄存器,此时,AB两个线程中 count 的值是一样的,A,B两个线程执行完后,返回的结果是同一个结果。
将程序进行修改,加入 synchronized 关键字:

 public class CountThread extends Thread{

    private int count = 0;

    @Override
    public synchronized void run() {
        count++;
        System.out.println(Thread.currentThread().getName() + " - " + count);
    }

}

测试程序不变,运行后,结果如下:

Thread-1 - 1
Thread-6 - 2
Thread-5 - 3
Thread-8 - 4
Thread-4 - 5
Thread-10 - 6
Thread-3 - 7
Thread-2 - 8
Thread-12 - 9
Thread-11 - 10
...
Thread-980 - 980
Thread-981 - 981
Thread-982 - 982
Thread-983 - 983
Thread-984 - 984
Thread-985 - 985
Thread-986 - 986
Thread-987 - 987
Thread-988 - 988
Thread-989 - 989
Thread-990 - 990
Thread-991 - 991
Thread-992 - 992
Thread-993 - 993
Thread-994 - 994
Thread-995 - 995
Thread-996 - 996
Thread-997 - 997
Thread-998 - 998
Thread-999 - 999
Thread-1000 - 1000

我们可以看到,Thread 的编号并不是按照先后顺序来执行的,这是因为先 start() 方法的线程并不一定先执行,而是由于CPU执行某个线程是具有不确定性的。
这里的结果,说明加入了 synchronized 关键字后,所有线程在同步方法中,是每次只有一个在执行的。最终结果也是正确的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值