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

标签 java multithreading locking wait

我有一个 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/

相关文章:

mysql - 等待锁定后应用的 CURRENT_TIMESTAMP - 值是多少?

java - 为什么map被调用多次?

java - 如何使用自定义类作为迭代器的类型变量?

Java参数,数组索引错误

c++ - 每 X 秒运行一个函数 C++

go - 互斥锁如何与单例一起使用?

java - 锁是否对同步执行相同的操作?

Java DAO 缓存

java - JPQL 新对象实例化

java - 我的 Produce Consumer 挂起