有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

避免在Java中丢失更新而不直接使用同步

我想知道是否有可能避免丢失更新问题,即多个线程更新同一日期,同时避免使用synchronized(x) { }

我将进行大量的添加和增量:

val++;
ary[x] += y;
ary[z]++;

我不知道java如何编译这些字节代码,如果一个线程可以在这些语句块中的一个字节中被中断。换句话说,这些语句是线程安全的吗

另外,我知道Vector类是同步的,但我不确定这意味着什么。以下代码是线程安全的,因为i位置的值不会在vec.get(i)vec.set(...)之间改变

class myClass {
  Vector<Integer> vec = new Vector<>(Integer);

  public void someMethod() {
    for (int i=0; i < vec.size(); i++)
      vec.set(i, vec.get(i) + value);
  }
}

提前谢谢


共 (2) 个答案

  1. # 1 楼答案

    为了线程化的目的,+++=被视为两个操作(四个用于doublelong)。因此,更新可能会相互冲击。不仅是一个,而且一个在错误时刻运行的调度程序可能会删除毫秒级的更新

    是你的朋友

    您的代码可以变得安全,前提是您不介意每个元素单独更新,并且不更改大小(!),作为:

    for (int i=0; i < vec.size(); i++) {
        synchronized (vec) {
            vec.set(i, vec.get(i) + value);
        }
    }
    

    如果您想向Vector添加调整大小,您需要将synchronized语句移到for循环之外,您也可以使用纯新的ArrayList。实际上,同步列表并没有多大用处

    但是你可以使用AtomicIntegerArray

    private final AtomicIntegerArray ints = new AtomicIntegerArray(KNOWN_SIZE);
    [...]
        int len = ints.length();
        for (int i=0; i<len; ++i) {
            ints.addAndGet(i, value);
        }
    }
    

    它的优点是没有锁(!)没有拳击。这个实现也很有趣,您需要理解它,并执行更复杂的更新(例如,随机数生成器)

  2. # 2 楼答案

    维克。set()和vec。get()是线程安全的,因为它们不会以丢失集和进入其他线程的方式设置和检索值。这并不意味着你的设置和获取将不受干扰地进行

    如果你真的要像上面的例子那样编写代码,你可能应该锁定一些东西。而且synchronized(vec) { }和其他的一样好。您在这里要求同步执行两个操作,而不仅仅是一个线程安全操作

    甚至是爪哇。util。同时发生的atomic只能确保一个操作(get或set)安全进行。你需要在一次操作中获得和增加