Java线程安全 - 多个原子操作?

时间:2017-01-12 18:18:19

标签: java multithreading

我只是一名非开发人员,可以成为开发人员,所以我的问题可能非常简单!

我只是测试Java多线程的东西,这不是真正的代码。我想知道如何在Java中同时更新两个成员变量,以防我们想要它们同步。举个例子:

public class Testing
{
  private Map<String, Boolean> itemToStatus = new ConcurrentHashMap<>();
  private Set<String> items = ConcurrentHashMap.newKeySet();

  public static void main(String[] args)
  {
    (new Testing()).start("ABC");
  }

  public void start(String name) {
    if (name.equals("ABC")) {
      itemToStatus.put(name, true);
      items.add(name);
    }
  }
}

在那种情况下(想象多线程,当然)我希望能够保证itemsitemToStatus的任何读取始终返回相同的内容。

因此,如果代码在行itemToStatus.put(name, true)中,而其他线程询问items.contains(name),则返回false。另一方面,如果其他线程询问itemToStatus.containsKey(name);它将返回true。我不希望如此,如果有意义,我希望他们两者都给出相同的价值?

如何将这两个变化原子化?这会有用吗?

if (name.equals("ABC")) {
    synchronised(this) {
        itemToStatus.put(name, true);
        items.add(name);
    }
}

尽管如此,我不明白为什么会这样。我认为你需要一个锁或什么的情况?

干杯!

2 个答案:

答案 0 :(得分:1)

只是同步写入不会起作用。您还需要同步(在同一对象上)对itemsitemToStatus集合的读取访问权限。这样,如果另一个线程正在更新两个集合的过程中,没有线程可以读取任何内容。请注意,以这种方式同步意味着您不需要ConcurrentHashMapConcurrentHashSet;简单的旧HashMapHashSet将起作用,因为您提供了自己的同步。

例如:

public void start(String name) {
    if (name.equals("ABC")) {
        synchronized (this) {
            itemToStatus.put(name, true);
            items.add(name);
        }
    }
}

public synchronized boolean containsItem(String name) {
    return items.contains(name);
}

public synchronized boolean containsStatus(String name) {
    return itemToStatus.containsKey(name);
}

这将保证containsItem返回的值也会由containsStatus返回,如果已经进行了此调用。当然,如果您希望返回值在一段时间内保持一致(如在第一次调用containsItem()然后再调用containsStatus()),则需要更高级别的同步。

答案 1 :(得分:0)

简短的回答是肯定的:通过同步代码块,就像在上一个代码片段中所做的那样,您使类成为线程安全的,因为该代码块是唯一一个读取或修改类状态的代码块(代表由两个实例变量)。 select <all-my-fields>, count(*) from ( select <all-my-fields> from mytable union all select <all-the-fields> from mybackuptable ) merged_data group by <all-my-fields> having count(*) = 1 的含义是您使用对象的实例(select <all-my-fields> from ( select max(source) source, <all-my-fields>, count(*) from ( select 1 source, <all-my-fields> from mytable union all select 2, source, <all-the-fields> from mybackuptable ) merged_data group by <all-my-fields> having count(*) = 1 ) minus_data where source = 1 )作为锁:当线程进入该代码块时,它获得锁定,阻止其他线程进入相同的代码块,直到当线程从代码块退出时,它会释放它。