Java同步方法与块
我试图更全面地理解Java中多线程的同步。我理解使用synchronized关键字背后的高级思想,以及它如何在线程之间提供互斥 唯一的一件事是,我在网上读到的以及在我的教科书中读到的大多数例子仍然能够正确地工作,即使你删除了synchronized关键字,这使得这个主题比我认为的更令人困惑Java同步方法与块,java,concurrency,synchronization,synchronized,concurrent-programming,Java,Concurrency,Synchronization,Synchronized,Concurrent Programming,我试图更全面地理解Java中多线程的同步。我理解使用synchronized关键字背后的高级思想,以及它如何在线程之间提供互斥 唯一的一件事是,我在网上读到的以及在我的教科书中读到的大多数例子仍然能够正确地工作,即使你删除了synchronized关键字,这使得这个主题比我认为的更令人困惑 有谁能给我一个具体的例子,说明不包括synchronized关键字会产生错误的结果?如有任何信息,将不胜感激12325号柜台应该是20000 此示例失败,因为对计数器的访问未正确同步。它可能以两种方式失败,
有谁能给我一个具体的例子,说明不包括synchronized关键字会产生错误的结果?如有任何信息,将不胜感激关于种族条件的问题是,如果你不进行适当的同步,它们不一定会发生——事实上,通常情况下它会工作得很好——但是一年后,在半夜,你的代码将与一个完全不可预知的bug一起崩溃,你不能复制,因为bug只会随机出现。
竞态条件之所以如此隐蔽,正是因为它们并不总是使程序崩溃,而且它们或多或少是随机触发的。通常可以通过增加迭代次数来触发竞态条件。这里有一个简单的例子,可以使用100次和1000次迭代,但在10000次迭代(有时)时失败(至少在我的四核机上)
公共级比赛
{
静态最终整数迭代=10000;
静态整数计数器;
公共静态void main(字符串[]args)引发InterruptedException{
系统输出打印项次(“开始”);
Thread first=新线程(new Runnable(){
@凌驾
公开募捐{
对于(int i=0;i>>12325号柜台应该是20000
此示例失败,因为对计数器的访问未正确同步。它可能以两种方式失败,可能在同一次运行中同时失败:
- 一个线程看不到另一个线程增加了计数器,因为它看不到新值
- 一个线程增加另一个线程读取当前值和写入新值之间的计数器。这是因为递增和递减运算符不是原子的
这个简单程序的修复方法是使用AtomicInteger
。由于增量的问题,使用volatile
是不够的,但是AtomicInteger
为增量、获取和设置等提供了原子操作。您研究过了吗?那页上有一个很好的例子。我看了一下这个例子,但它有点抽象。我理解比赛条件背后的想法,我只是想看看一个例子来帮助我更好地理解它
public class Race
{
static final int ITERATIONS = 10000;
static int counter;
public static void main(String[] args) throws InterruptedException {
System.out.println("start");
Thread first = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < ITERATIONS; i++) {
counter++;
}
}
});
Thread second = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < ITERATIONS; i++) {
counter++;
}
}
});
first.start();
second.start();
first.join();
second.join();
System.out.println("Counter " + counter + " should be " + (2 * ITERATIONS));
}
}
>>> Counter 12325 should be 20000