Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/386.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java线程安全-多原子操作?_Java_Multithreading - Fatal编程技术网

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

Java线程安全-多原子操作?,java,multithreading,Java,Multithreading,我只是一个非开发人员,扮演开发人员的角色,所以我的问题可能非常简单 我只是测试Java多线程的东西,这不是真正的代码。我想知道如何在Java中同时更新两个成员变量,以防我们希望它们都同步。例如: public class Testing { private Map<String, Boolean> itemToStatus = new ConcurrentHashMap<>(); private Set<String> items = Concurre

我只是一个非开发人员,扮演开发人员的角色,所以我的问题可能非常简单

我只是测试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);
    }
  }
}
尽管如此,我还是不明白为什么这会奏效。我想你需要锁什么的


干杯

仅仅同步写入是行不通的。您还需要同步(在同一对象上)对
项状态
集合的读取访问。这样,如果另一个线程正在更新这两个集合,则没有线程可以读取任何内容。请注意,以这种方式进行同步意味着您不需要
ConcurrentHashMap
ConcurrentHashSet
;普通的
HashMap
HashSet
将起作用,因为您提供了自己的同步

例如:

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);
}

这将保证如果调用了该调用,
containsStatus
也会返回由
containsSitem
返回的值。当然,如果希望返回值随时间保持一致(如首先调用
containsItem()
然后调用
containsStatus()
),则需要更高级别的同步。

简单的回答是肯定的:通过同步代码块,就像在上一个代码段中所做的那样,您使类成为线程安全的,因为该代码块是唯一读取或修改类状态(由两个实例变量表示)的代码块。
synchronized(this)
的意思是使用对象的实例(
this
)作为锁:当一个线程进入该代码块时,它将获得锁,防止其他线程进入同一代码块,直到线程从该代码块退出时释放它为止。

多线程不是“非常简单的”在每次读取对象时,您都需要同步块。对它加1并不简单!同样的道理,它也不是一件可以零零碎碎地捡起来的东西。与可以进行实验的单线程编码不同,使用多线程技术很容易在每次测试时都能找到有效的方法,然后在该领域中有0.07%的时间出现可怕的、令人困惑的失败。如果你有兴趣了解它,我强烈建议你读一本书或类似的深度指南。看看这个和这个@CraigR8806哈哈,到目前为止,编程是“简单的”。我希望多线程也是:(你的意思是将
synchronized
添加到变量声明中吗?这会有什么帮助?介意提供一些示例代码吗?等等,如果你将
synchronized
添加到方法中,你保证了对该方法的原子访问,对吗?但这并不意味着你没有读取旧值,是吗?对不起,我说得通吗?比如,一个thread调用
containsItem
,而另一个线程正在执行
itemToStatus.put(name,true);
,这将导致不同步状态,对吗?@Will-如果同步正确,调用
containsItem()
的线程将被阻止,直到另一个线程完成更新调用为止(反之亦然)。将整个写入逻辑作为单个块进行同步以将其视为原子,这一点非常重要。(同样,如果多个读取需要以原子方式进行,则需要将其作为单个块进行同步。)@这正是
synchronized
阻止的部分原因。我会仔细阅读这个主题,在少量的信息中,人们真的无法完全掌握Java的内存模型和多线程特性。感谢Jacopo的回复。我有点理解它是线程安全的,但是如果其他人阅读第一个变量
itemToStatus项时de>。添加(名称)
,这不是一个问题吗?即使是同步的
?也不会阻止其他线程读取值,除非它们也在同一个锁对象上同步。确切地说:类中读取或修改两个字段的所有代码都需要使用同一个锁包装在一个同步块中,在您的情况下,这就是这是“this”引用。RiiiiiiiIlight,好的…所以通过执行
同步(this)
您可能会“锁定整个对象”直到该块完成,对吗?所以任何其他线程在其他任何地方执行任何操作都将在那里停止并等待该块完成,对吗?当然,听起来可能会很慢,但请让我知道我之前的评论是否正确
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);
}