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

这个同步代码会导致不必要的线程等待吗?

池麒
2023-03-14

我们有一个应用程序,它有一个包含通过数据库填充的成员的类。这里有一个典型的例子。

private AtomicBoolean data1Initialized = new AtomicBoolean(false);
protected SomeSynchronizedDataStructure<Object> data1 = <initializeit>;

protected final synchronized void initData1() {
    if (data1Initialized.compareAndSet(false, true)){
        // Populate data1 data structure from database
    }
}
public SomeSynchronizedDataStructure<Object> getData1(){
    initData1();
    return data1;
}

对于data1、data2、data3…dataN,我们有相同的模式。每个dataStructure都与另一个无关,它们只是在同一个类中。此数据是跨多个线程访问的。关于此模式的几个问题:

同步方法将使线程必须等待跨所有不同dataN的布尔检查,对吗?哪个是不必要的?

数据结构需要同步吗?数据在应用程序的整个生命周期中都不会改变。我认为只有初始化它才需要同步,访问可能会发生不同步。

对我个人来说最重要的是

这会导致僵局吗?我认为没有,但我对线程没有经验。

共有2个答案

马业
2023-03-14

同步方法将使线程必须等待所有不同数据的布尔检查,对吗?

正确。

哪个是不必要的?

是的,这是不必要的,因为数据不相关。

数据结构需要同步吗?数据在应用程序的整个生命周期中都不会改变。我认为只有初始化它才需要同步,访问可能会发生不同步。

再次正确。BarrySW19的答案为您提供了无需同步即可安全初始化它的模式。

对我个人来说最重要的是

这会导致僵局吗?我认为没有,但我对线程没有经验。

它本身不会造成僵局。但是,如果其中一个数据初始化方法调用了在另一个监视器上同步的其他内容(称为m),同时其他线程拥有m,现在尝试初始化其中一个dataN,则称为死锁。

章茂
2023-03-14

当您在创建课程时进行初始化时,您只需要:

public class DataHolder {
    // Note: 'final' is needed to ensure value is committed to memory before DataHolder
    private final SomeSynchronizedDataStructure<Object> data1 = <initializeit>;

    public SomeSynchronizedDataStructure<Object> getData1(){
        return data1;
    }
}

因为“初始化”代码将在类的构造函数中运行,所以您知道它将在您有一个可用于传递的类句柄时准备好。例如:

DataHolder dataHolder = new DataHolder();
// dataHolder has already created the data structure by the time I do...
dataHolder.getData1();

如果您确实想进行延迟加载,您可以简单地使用synchronized:

public class DataHolder {
    private SomeSynchronizedDataStructure<Object> data1;

    public synchronized SomeSynchronizedDataStructure<Object> getData1() {
        // synchronized guarantees each thread will see "data1" just as the
        // last thread left it.
        if(data1 == null) {
            data1 = initializeit();
        }
        return data1;
    }
}
 类似资料:
  • 我使用blocking queue(LinkedBlockingQueue)在几个线程之间同步数据。请看下图。 主线程是一个生产者,它产生对象,然后将它们放入每个消费者的队列中(线程2-10)。需要强调的是,每个消费者都有自己的队列,每个产生的对象都将进入所有消费者的队列。 生产者的运行速度比使用者快得多,因此我们可以假设在使用者运行期间队列不应该为空。当任何使用者的队列达到其容量时,生产者将被阻

  • 我最近阅读了有关async/await的文章,我感到困惑的是,我阅读的许多文章/帖子都指出,在使用async await(示例)时不会创建新线程。 我创建了一个简单的控制台应用程序来测试它 以下代码的输出是: 我想知道,如果没有创建其他线程,部分在哪里运行?如果它运行在同一个线程上,难道它不应该因为长的I/O请求而阻塞它吗?或者编译器足够聪明,如果它需要太长的时间,就可以将该操作移到另一个线程上,

  • 我很困惑。一个或多个怎么能在单个线程上并行运行?我对并行性的理解显然是错误的。 一些我无法理解的MSDN: 异步和等待关键字不会导致创建额外的线程。异步方法不需要多线程,因为异步方法不会在自己的线程上运行。该方法在当前同步上下文上运行,并且仅在方法处于活动状态时才在线程上使用时间。 .. 以及: 在启动任务和等待任务之间,您可以启动其他任务。其他任务隐式并行运行,但不会创建其他线程。

  • 我做了几个线程转储,发现有16个线程在等待同一个锁,例如: “__ejb-thread-pool1”守护进程prio=6 tid=0x39657c00 nid=0x1c08在条件[0x3297f000]java.lang.thread.state:waiting(parking)在sun.misc.unsafe.park(本机方法)-在java.util.concurrent.locks.lock

  • 我正在为一个大型应用程序编写自动化测试。这些测试中的一些很容易成为<code>异步,它只提供<code>async 测试应用程序的一些关键方面如下: 这是一个巨大的ASP.NET应用程序(尽管代码在通过单元测试执行时没有在ASP.NET上下文中运行)。 在其核心中,它严重依赖于每个线程缓存上下文信息(例如活动用户的整个权限方案)的静态对象。 现在,我的问题是当在方法中使用时,延续可能发生在与以前不

  • 我遇到了一些使用c#的/关键字进行异步编程的最佳实践(我是c# 5.0的新手)。 给出的建议之一如下: 稳定性:了解您的同步上下文 ...一些同步上下文是不可重入的和单线程的。这意味着在给定时间只能在上下文中执行一个工作单元。这方面的一个例子是Windows UI线程或ASP.NET请求上下文。在这些单线程同步上下文中,很容易死锁。如果您从单线程上下文中生成一个任务,然后在上下文中等待该任务,您的