您的位置:首页 > 编程语言 > Java开发

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

2018-01-17 16:37 381 查看
首先举一个例子:

定义一个 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 的值读入寄存器中;
二.将 count 加 1;
三.将 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 关键字后,所有线程在同步方法中,是每次只有一个在执行的。最终结果也是正确的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: