我有一个java多线程问题。我有 2 个线程访问一个内部有一个 for 循环的 methodA(),并且在循环中调用一个 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 等。
任何解决此“无需等待即可锁定”问题的输入将不胜感激。
非常感谢您的帮助。
一些澄清以改进答案。
- methodA() 和 methodB() 都在同一个类中。methodB() 不在 Object 类中。
- 实际上线程 A 和线程 B 是调用包括 A 和 B 在内的许多方法的计时器线程。因此线程级锁(因为线程每 15 分钟左右调用一次,并且有可能之前不会完成 methodA() 的第一次执行第二次调用它)。
- methodB(Obj1) 始终采用 Object1 参数并且必须锁定它。原因是,在这个类中还有其他方法,比如 methodC(Obj1) 和 methodD(Obj1),它们也接受 Object1 参数。对于 Object1 的同一实例,这些方法不应同时执行。因此需要锁定 Object1 参数。
- 发现methodB(Obj1 obj) 已经被obj1 上的线程A() 锁定的线程B 需要以某种方式再次调用methodB() 但使用不同的对象,比如obj2。一旦与其他人一起完成,它应该回到 obj1 。