Java多线程-无等待锁定

Java多线程-无等待锁定,java,multithreading,locking,wait,Java,Multithreading,Locking,Wait,我有一个java多线程问题。我有两个线程访问methodA(),该methodA()内部有for循环,循环中调用methodB()。方法A应该使用线程名称锁锁定,方法B应该在方法B操作的对象id上锁定。检查下面的代码 当前代码 private static final ConcurrentHashMap<Object, Object> LOCKS = new ConcurrentHashMap<Object, Object>(); p

我有一个java多线程问题。我有两个线程访问methodA(),该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>
      }   
    }
私有静态最终ConcurrentHashMap锁=新ConcurrentHashMap();
私有无效方法a(){
LOCKS.putIfAbsent(Thread.currentThread().getName(),new Object())
已同步(LOCKS.putIfAbsent(Thread.currentThread().getName(),new Object()){
for(通过所有对象循环){
方法b(对象1);
}
}
}
私有无效方法B(Object1 Object1){
LOCKS.putIfAbsent(object1.getObjectId(),new Object())
已同步(LOCKS.putIfAbsent(object1.getObjectId(),new Object()){
//
}   
}
我编写上述代码是为了确保两个不同的线程能够并行访问methodA(),但不能在methodB()中同时处理同一个Object1(methodA()调用)。 ie;虽然我希望线程A和线程B同时访问methodA(),而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()不在对象类中
  • 实际上,线程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

  • 你能做的最好的事情就是保持简单

    应该使用线程名称锁来锁定方法A

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

    已同步(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();
        }
    }
    
    private void methodA(){
    List objects=new ArrayList(this.objectList);
    while(true){
    for(迭代器iter=objects.Iterator():objects)
    if(object1.methodB())
    iter.remove();
    如果(objects.isEmpty())中断;
    睡眠(在再次尝试之前等待一段时间);
    }
    }
    //为Object1上课
    最终锁定=新的可重入锁定();
    公共布尔方法B(){
    如果(!lock.tryLock())
    返回false;
    试一试{
    //做这个
    返回true;
    }最后{
    lock.unlock();
    }
    }
    
    根据您想要如何处理无法锁定的对象,您可以将它们添加到后台执行器服务中。您可以让methodA重复调用失败的所有剩余对象


    理想情况下,您会找到一种方法,以尽量减少锁定的时间,甚至完全消除锁定的需要。e、 像AtomicReference和CopyOnWriteArrayList这样的类是线程安全的,没有锁的。

    你能做的最好的事情就是保持简单

    应该使用线程名称锁来锁定方法A

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

    已同步(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();
        }
    }
    
    private void methodA(){
    List objects=new ArrayList(this.objectList);
    while(true){
    for(迭代器iter=objects.Iterator():objects)
    if(object1.methodB())
    iter.remove();
    如果(objects.isEmpty())中断;
    睡眠(在再次尝试之前等待一段时间);
    }
    }
    //为Object1上课
    最终锁定=新的可重入锁定();
    公共布尔方法B(){
    如果(!lock.tryLock())
    返回false;
    试一试{
    //在…上工作