gpt4 book ai didi

Java多线程-无需等待的锁定

转载 作者:行者123 更新时间:2023-12-01 16:33:31 24 4
gpt4 key购买 nike

我有一个 java 多线程问题。我有 2 个线程访问 methodA(),其中有一个 for 循环,并在循环中调用 methodB()。方法 A 应该使用线程名锁来锁定,方法 B 应该锁定在方法 B 所操作的对象 id 上。检查下面的代码。

当前代码

        private static final ConcurrentHashMap<Object, Object> LOCKS = new ConcurrentHashMap<Object, Object>();   
private void methodA(){
LOCKS.putIfAbsent(Thread.currentThread().getName(), new Object()))
synchronized (LOCKS.putIfAbsent(Thread.currentThread().getName(), new Object())) {
for(loop through all objects) {
methodB(Object1);
}
}
}

private void methodB(Object1 object1) {
LOCKS.putIfAbsent(object1.getObjectId(), new Object()))
synchronized(LOCKS.putIfAbsent(object1.getObjectId(), new Object())){
//<Work on object1>
}
}

我完成了上述代码,以确保 2 个不同的线程应该能够并行访问 methodA(),但不应在 methodB()(由 methodA() 调用)中一次处理同一个 Object1。IE;虽然我希望线程 A 和线程 B 同时访问 methodA() ,这反过来会循环遍历 'for' 循环中的所有对象,并通过调用 methodB() 对每个对象进行操作,但我不希望线程 A 和 B一次作用于同一个对象实例。因此,上面的代码根据对象实例 ID 锁定 methodB()。

需要改进。

在上面的代码中,如果线程 A 和线程 B 来到 methodB() 并发现它们都想要处理同一个对象“obj1”,那么现在使用上面的代码,要么线程 A 将等待,要么线程 B 将等待另一个完成取决于谁首先到达并锁定了 methodB()。

但想象一下这样一种情况,线程 A 首先获得锁并执行 methodB() 需要 9 个小时才能完成处理“obj1”。在这种情况下,线程 B 需要等待整整 9 个小时才有机会执行 methodB() 并从而处理“obj1”。

我不希望这种事发生。线程 B,一旦发现 methodB() 被线程 A 锁定在“obj1”的名称中,就应该继续(并稍后返回到 obj1)尝试锁定和处理其他对象。 IE;它应该尝试处理“for”循环中的其他对象,例如对象列表中的 obj1、obj2 等。

任何解决此“无需等待的锁定”问题的意见都将受到赞赏。

提前非常感谢您的帮助。

一些改进答案的说明。

  1. methodA() 和 methodB() 都在同一个类中。 methodB() 不在 Object 类中。
  2. 实际上,线程 A 和线程 B 是定时器线程,它们调用包括 A 和 B 在内的许多方法。因此线程级锁(因为线程每 15 分钟左右被调用一次,并且有可能第一次执行 methodA() 不会在第二次调用之前完成)。
  3. methodB(Obj1) 始终采用 Object1 参数,并且必须锁定它。原因是,在这个类中还有其他方法,例如 methodC(Obj1) 和 methodD(Obj1) 也接受 Object1 参数。对于 Object1 的同一个实例,不应同时执行这些方法。因此需要锁定 Object1 参数。
  4. 线程 B 发现 methodB(Obj1 obj) 已被线程 A() 在 obj1 上锁定,需要以某种方式再次调用 methodB(),但使用不同的对象(例如 obj2)。一旦完成其他任务,它应该返回 obj1。

最佳答案

你能做的最好的事情就是让事情变得简单。

The method A should be locked using a thread-name lock

只有锁定共享对象才有意义。锁定线程本地锁是没有意义的。

synchronized(LOCKS.putIfAbsent(object1.getObjectId(), new Object()))

第一次运行时将返回 null 并抛出 NullPointerException。

<小时/>

我会将代码替换为

private void methodA(){  
List<Object1> objects = new ArrayList<>(this.objectList);
while(true) {
for(Iterator<Object1> iter = objects.iterator() : objects)
if(object1.methodB())
iter.remove();
if(objects.isEmpty()) break;
Thread.sleep(WAIT_TIME_BEFORE_TRYING_AGAIN);
}
}

// in class for Object1
final Lock lock = new ReentrantLock();

public boolean methodB() {
if (!lock.tryLock())
return false;
try {
// work on this
return true;
} finally {
lock.unlock();
}
}

根据您想要如何处理无法锁定的对象,您可以将它们添加到后台 ExecutorService。您可以让 methodA 重复调用失败的所有剩余对象。

理想情况下,您会找到一种方法来最小化锁定时间,甚至完全消除对锁定的需要。例如AtomicReference 和 CopyOnWriteArrayList 等类是线程安全且无锁的。

关于Java多线程-无需等待的锁定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11882398/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com