同步块中的原子变量

时间:2018-05-22 08:33:38

标签: java synchronization synchronized thread-synchronization

我指的是Java语言,但我认为它也可以涉及其他语言。

问题是:将原子变量放在同步块中是否有意义?或者同步块不会同时由两个线程执行的事实足以保证在synchronized块中执行的操作是原子的吗? (实施例1与实施例2)

示例1:

public class SharedVariables {
  public static AtomicInteger i;
}

public class MyThread extends Thread {
  public void run() {
    synchronized(SharedVariables.i) {
      i.getAndIncrement();
    }
  }
}

示例2:

public class MyIntegerWrapper {
  public int i;
  public void increment() {
    this.i++;
  }
}

public class SharedVariables {
  public static MyIntegerWrapper i;
}

public class MyThread extends Thread {
  public void run() {
    synchronized(SharedVariables.i) {
      i.increment();
    }
  }
}

5 个答案:

答案 0 :(得分:2)

不是自己没有。但是,如果您正在执行涉及线程安全类(如AtomicInteger)和其他变量(即使它们是其他AtomicIntegers)的操作,您可能需要这样做。

AtomicInteger保证对它的操作是线程安全的和原子的,而不需要做任何事情。但是,让我们说你增加一个并递减另一个,它们的总和总是需要相同。您有2个原子操作,但要将它们组合成单个原子操作,您需要进行额外的同步。只有这样,你才能确定其他线程会读取这些变量的常数总和。

在将手动同步与java.util.concurrent类结合使用时,我仍然要小心,因为并发类提供的解决方案最可能是更清晰的解决方案。

答案 1 :(得分:0)

synchronized在您的第一个代码中不是必需的,原子变量的保证就足够了。

您的第二个代码有一个问题:int变量是公开的,因此您无法保证始终从synchronized块调用它。

答案 2 :(得分:0)

原子变量使用非阻塞算法(它使用比较和交换机制),所以你不应该在synchronized块中使用它,而是尝试尽可能使用原子变量以获得更好的性能。

答案 3 :(得分:0)

在您的示例中,完全可以使用AtomicInteger而不是synchronizedMyIntegerWrappersynchronized内。

但一般情况下,它取决于您的可变可见范围。例如,如果您决定使用MyIntegerWrapper而不是AtomicInteger,则必须确保没有其他方法在没有同步的情况下使用它。

另外选择什么取决于不同线程修改变量的频率。 AtomoicInteger使用 compare-and-set (或只是cas)操作而不是同步。 CAS被认为更快,因为与输入synchronized块相比,开销更少,但是在高争用情况下(当有许多线程试图同时修改此变量时)synchronized块可以更有效率。同样synchronized为jvm提供了一些优化空间,比如锁定粗化。因此,选择AtomicInteger而不是synchronized时,请记住这一点。

答案 4 :(得分:0)

在第一个示例中,您使用两个同步。

AtomicInteger实现" Non-blocking synchronization algorithm"

完全看起来免费算法,允许单个线程饿死但保证系统范围的吞吐量。

此算法适用于机器指令。例如,在x86(自80486)和Itanium体系结构中,这是作为比较和交换(CMPXCHG)指令实现的。

你的关键词"同步"是多余的,甚至不允许工作无锁算法,这提供了很好的优势。

因此,在您的情况下,不要使用synchronized块,请使用AtomicInteger。