当前位置: 首页 > 知识库问答 >
问题:

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

林弘壮
2023-03-14

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

我只是在测试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);
    }
  }
}

在这种情况下(当然,想象一下多线程),我希望能够保证对< code>items和< code>itemToStatus的任何读取总是返回相同的结果。

因此,如果代码在< code>itemToStatus.put(name,true)行中,并且其他线程询问< code > items . contains(name),它将返回false。另一方面,如果另一个线程请求< code > itemtostatus . contains key(name);它将返回true。我不希望这样,我希望它们给出相同的值,如果这有意义的话?

我怎样才能使这两个变化原子化?这行吗?

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

不过,我不明白为什么这会奏效。我想这就是你需要锁什么的情况?

干杯

共有2个答案

师向文
2023-03-14

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

濮丰
2023-03-14

仅仅同步写入是不起作用的。您还需要同步(在同一个对象上)对项目itemToState集合的读取访问。这样,如果另一个线程正在更新这两个集合,则没有线程可以读取任何内容。请注意,以这种方式同步意味着您不需要Con的HashMapCon的HashSet;普通的旧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);
}

这将保证如果进行了该调用,则< code>containsItem返回的值也将由< code>containsStatus返回。当然,如果您希望返回值在一段时间内保持一致(比如首先调用< code>containsItem(),然后调用< code>containsStatus()),您将需要更高级别的同步。

 类似资料:
  • 问题内容: 最近,我正在阅读一个教程,其中遇到了一条声明: “Java语言规范保证了读取或写入的变量是一个原子操作(除非该变量的类型的或)类型的操作变量或者是只有当它们与申报原子的关键字。” 或提供类似的方法,并且其是原子的。 我对以上声明感到有些困惑。.请您澄清一下 何时使用 或 使用类。 问题答案: 否则(与作为一个)是一个原子操作。但是执行操作不是原子操作,因为它需要读取a的值,递增和写入a

  • 原子操作是否足够安全,可以在多线程应用程序中使用它,而不会导致竞争条件和其他并发问题?假设我们不担心可见性(我们从CPU读取/写入所有内容)。

  • 我找到了关于线程安全的代码,但它没有来自给出示例的人的任何解释。我想知道为什么如果我不在“count”之前设置“synchronized”变量,那么count值将是非原子的(总是=200是期望的结果)。谢谢

  • 如果有多个Java线程同时写入同一个套接字实例,这会影响从同一个套接字读取的对象的完整性吗?例如,对象的内容是否会被弄乱等。对象的顺序可以是随机的。

  • 问题内容: 我从一个非常简单的多线程示例开始。我试图做一个线程安全的计数器。我想创建两个线程,使计数器间歇地增加到1000。以下代码: 据我所知,while循环现在意味着只有第一个线程才能访问计数器,直到达到1000。输出: 我该如何解决?如何获得共享计数器的线程? 问题答案: 两个线程都可以访问您的变量。 您看到的现象称为线程饥饿。输入代码的受保护部分后(很抱歉,我之前错过了它),其他线程将需要

  • 我们正在尝试使用以下查询将数据流式传输到postgres 11: 基本上“在表中插入记录,如果它已经存在 - 我们希望将此查询连接到消息队列,并在多个实例中的高并发环境中运行它。使用此查询,可能会从不同的连接访问同一行。对我们来说,只有具有最高交付时间戳的项目最终才能进入表是至关重要的 根据文件: 在冲突时,DO UPDATE保证原子插入或更新结果;如果没有独立的错误,那么即使在高并发的情况下,这