当前位置: 首页 > 面试题库 >

实践中的Java并发-示例14.12

唐炳
2023-03-14
问题内容
// Not really how java.util.concurrent.Semaphore is implemented
@ThreadSafe
public class SemaphoreOnLock {
    private final Lock lock = new ReentrantLock();
    // CONDITION PREDICATE: permitsAvailable (permits > 0)
    private final Condithtml" target="_blank">ion permitsAvailable = lock.newCondition();
    @GuardedBy("lock") private int permits;

    SemaphoreOnLock(int initialPermits) {
        lock.lock();
        try {
            permits = initialPermits;
        } finally {
            lock.unlock();
        }
    }

/* other code omitted.... */

我对上面的示例有一个疑问,该示例是从 练习 清单14.12计数使用锁实现的信号量的 Java并发中 提取的。

我想知道为什么我们需要在构造函数中获取锁(如所示的lock.lock()被调用)。据我所知,构造函数是 原子的
(引用转义除外),因为没有其他线程可以获取该引用,因此,其他线程看不到一半构造的对象。因此,我们不需要构造函数的同步修饰符。此外,只要对象被安全发布,我们也不必担心
内存可见性

那么,为什么我们需要在构造函数中获取ReentrantLock对象?


问题答案:

半构造对象对其他线程不可见

这不是真的。如果对象具有任何 非最终/易失性
字段,则该对象在构造时对其他线程可见。因此,其他线程可能会看到一个默认值,permits0可能与当前线程不一致的默认值。

Java内存模型为不可变对象(仅具有最终字段的对象)提供了 初始化安全性
的特殊保证。对另一个线程可见的对象引用并不一定意味着该对象的状态对于使用线程是可见的-JCP $3.5.2

从清单3.15中的Java并发实践中:

似乎在构造函数中设置的字段值似乎是写入这些字段的第一个值,因此没有“旧”值被视为过时的值,但在子类构造函数运行之前, Object
构造函数首先将默认值写入所有字段。因此,可以将字段的 默认 值视为 过时的 值。



 类似资料:
  • 我对上面的示例有一个问题,该示例是从Java并发实践清单14.12使用锁实现的计数信号量中提取的。 我想知道为什么我们需要获取构造函数中的锁(如图所示lock.lock()被调用)。据我所知,构造函数是原子的(除了引用转义),因为没有其他线程可以获得引用,因此,半构造对象对其他线程不可见。因此,我们不需要构造函数的同步修饰符。此外,我们也不需要担心内存可见性,只要对象安全发布。 那么,为什么我们需

  • 问题内容: Brian Goetz的Java Concurrency in Practice提供了一个有效的可伸缩缓存供并发使用的示例。这是该类的代码: 可能是个愚蠢的问题,但有人能告诉我该类的并发用法吗?喜欢在主? 干杯,Agata 问题答案: 这是一个计算阶乘的示例: 因此,如果两个线程尝试在完全相同的时间计算相同的阶乘,则由于线程安全,因此只有其中一个将实际执行计算。第二个线程将简单地获取第

  • 问题内容: 在《 Java Concurrency In Practice》中,作者指出 不变对象可以通过任何机制发布 不可变对象可以在没有附加同步的情况下被任何线程安全地使用,即使不使用同步来发布它们。 这是否意味着以下成语可以发布不可变对象? 会有数据竞赛吗?(这意味着线程B可能无法在线程A添加的列表中看到不可变对象) 非常感谢你。 此外,作者说,如果Resource是不可变的,以下代码是安全

  • null 对于此问题的第二部分,将在另一个问题(单击此处)中详细讨论

  • 问题内容: 我有以下来自GoByExamples的并发渠道示例 Java中是否有等同的东西?我本以为实现同一件事会更加冗长。 问题答案: 语句 是 在Go中在语言语法级别引入并发的原因。并发函数调用可以(和通常完成)在库级别使用辅助函数(例如和通道)实现,就像在大多数其他语言中使用互斥或​​锁定的数据结构一样。但是声明不能。

  • 问题内容: 首先,我将提供指向我将要讨论的源代码的链接,因为复制/粘贴会使该问题页面过长。 在JCIP的代码清单5.15 http://jcip.net/listings/CellularAutomata.java中,我认为在某些主要方法中,将创建一个CellularAutomata对象,然后在该对象上调用start()。 但是,这样做可以吗?调用对象的start方法时,它将使用Worker实例创