【问题标题】:Call synchronised on a function in java在java中的函数上调用同步
【发布时间】:2018-02-09 08:53:59
【问题描述】:

有没有一种方法可以在代码块上调用同步(或类似的东西)。例如(伪代码),

public int getA(int id) {
    if (flag) {
        return synchronized(fetchA(id))
    } else {
        return fetchA(id)
    }
}

public int fetchA(int id) {
    if (map.get(id) == null) {
        p = generate(id)
        map.put(id, p)  
        return map.get(id)
    } else {
        return map.get(id)
    }
}

在这种情况下,如果 flag 设置为 true,我希望函数对对象 map 进行锁定,否则不进行锁定。我读过同步只对对象进行锁定。还有什么我可以用来代替同步的吗?

【问题讨论】:

  • 你可以打开一个同步块synchronized(this) { fetchA(id); }如果这是你的要求

标签: java multithreading concurrency


【解决方案1】:

在对象上同步是完全正确的做法。在您的情况下,共享对象是map

你可以做一个

synchronized(map) {
    return fetchA(id);
}

锁定是某种契约:如果您访问map,那么您必须锁定它。这可能很麻烦并且容易出错。因此,更好的选择是在fetchA() 方法中锁定和释放,例如

public int fetchA(int id) {
    synchronized(map) {
        if (map.get(id) == null) {
            p = generate(id)
            map.put(id, p)  
            return map.get(id)
        } else {
            return map.get(id)
        }
    }
}

这样任何其他方法都可以简单地调用fetchA(),而无需意识到需要锁定。 另一种方法是声明函数同步。这样当时只有一个线程可以进入函数。

public synchronized int fetchA(int id) { ... }

话虽如此,请注意嵌套锁定。这是产生死锁的好方法。

【讨论】:

  • 为什么你建议的第一种方法容易出错? synchronized(map) { return fetchA(id); }我其实在考虑用那个
  • 很容易忘记锁定。如果您不使用锁,Java 将不会做任何事情来阻止对共享数据结构的访问。因此,您的程序大部分时间都可以完美运行。并且时不时地你会遇到奇怪的效果。因此,我所做的是正确的,但其他功能可能也想访问map。尤其是如果该代码是其他人在项目的后期添加的,忘记同步访问非常容易
【解决方案2】:

要回答您的直接问题:只需使用 synchronized 块:

synchronized (something) {
  return fetchA(id);
}

但你的方法一开始就不是很好。一方面,computeIfAbsent method 与您的 fetchA 方法完全相同:

public int fetchA(int id) {
    return map.computeIfAbsent(id, k -> generate(k));
}

另一方面,flag 似乎将成为实例的常量,因为仅在某些时候以同步方式访问它是没有意义的。

所以,根据构造函数中的标志选择Map 实现:

if (flag) {
  map = new ConcurrentHashMap<>();
} else {
  map = new HashMap<>();
}

然后根本不用担心是否需要在方法中进行同步:

public int getA(int id) {
  return map.computeIfAbsent(id, k -> generate(k));
}

【讨论】:

  • 使用JAVA7,因此不能使用computeIfAbsent
【解决方案3】:

您可以使用 ConcurrentHashMap。但是如果一个线程试图修改它而另一个线程正在迭代它,它将抛出“ConcurrentModificationException”。

对于代码块级别,您可以使用四种类型

Instance methods
enter code here
Static methods
Code blocks inside instance methods
Code blocks inside static methods

更多信息请参考:Code block level synchronization

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-25
    • 2015-03-19
    • 2020-12-20
    • 1970-01-01
    • 2014-02-05
    • 1970-01-01
    • 1970-01-01
    • 2013-07-12
    相关资源
    最近更新 更多