有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java静态数组变量需要锁定吗?

假设我有一个静态变量,它是一个大小为5的数组。 假设我有两个线程,T1和T2,它们都试图改变数组索引0处的元素。然后使用索引0处的元素。 在这种情况下,我应该锁定数组,直到T1使用完元素,对吗

另一个问题是假设T1和T2已经在运行,T1首先访问索引0处的元素,然后锁定它。但就在T2试图访问索引0处的元素之后,T1还没有解锁索引0。那么在这种情况下,为了让T2访问索引0处的元素,T2应该做什么?T2应该在T1解锁数组的索引0后使用回调函数吗


共 (6) 个答案

  1. # 2 楼答案

    不锁定变量;你锁定了一个互斥锁,它可以保护 特定范围的代码。规则很简单:如果有线程 修改一个对象,并且有多个线程访问它(例如 任何原因),所有访问都必须完全同步。照常 解决方案是定义一个互斥来保护变量request 一把锁在上面,一旦进入完毕,就释放锁。 当一个线程请求锁时,它将被挂起,直到该锁被释放 已经获释

    在C++中,通常使用RAII来确保锁是 释放,无论块如何退出。在爪哇, 同步块将在开始时获取锁 (等待它可用),并在 程序离开了块(无论出于什么原因)

  2. # 3 楼答案

    当有多个线程访问某个对象时,可以使用synchronize(锁)

    第二个线程将阻塞,直到第一个线程释放锁(退出同步块)

    如果不想让线程阻塞,可以使用java.util.concurrent.locks和非阻塞检查进行更细粒度的控制

  3. # 4 楼答案

    java中的同步(从技术上讲)不是拒绝其他线程访问某个对象,而是确保在使用同步锁的线程之间(一次)唯一地使用该对象。因此,T2可以在T1拥有同步锁的情况下访问对象,但在T1释放同步锁之前,T2将无法获得同步锁

  4. # 5 楼答案

    1)基本上是的。您不必锁定数组,您可以在更高的粒度级别上锁定(例如,如果它是一个私有变量,则锁定封闭类)。重要的是,如果不持有相同的锁,代码的任何部分都不会试图修改或读取数组。如果违反此条件,可能会导致未定义的行为(包括但不限于看到旧值、看到从未存在的垃圾值、抛出异常和进入无限循环)

    2)这在一定程度上取决于您使用的同步方案和所需的语义。使用标准的synchronized关键字,T2将无限期阻塞,直到T1释放监视器,此时T2将获取监视器并继续同步块内的逻辑

    如果希望在争用锁时对行为进行更细粒度的控制,可以使用显式Lock对象。这些提供了tryLock方法(都有一个超时,并立即返回),根据是否可以获得锁返回truefalse。因此,如果没有立即获得锁,您可以测试返回值并采取任何您喜欢的操作(例如注册回调函数、递增计数器以及在重试之前向用户提供反馈等)

    然而,这种定制反应很少是必要的,并且显著地增加了锁定代码的复杂性,更不用说,如果您忘记始终在finally块中释放锁,并且仅在成功获取锁时,错误的可能性很大,等等。作为一般规则,只需使用synchronized,除非/直到您能够证明它为应用程序所需的吞吐量提供了一个显著的瓶颈

  5. # 6 楼答案

    I should lock the array until T1 is finished using the element right?

    是的,为了避免比赛条件,这是个好主意

    what should T2 do

    查看数组,然后读取值。现在你知道没有其他人可以修改它。当使用诸如monitors之类的锁时,系统会自动保留队列。因此,如果T2试图访问被T1锁定的对象,它将阻塞(挂起),直到T1释放锁为止

    示例代码:

    private Obect[] array;
    private static final Object lockObject = new Object();
    
    public void modifyObject() {
        synchronized(lockObject) {
           // read or modify the objects
        }
    }
    

    从技术上讲,您还可以在阵列本身上进行同步