Java锁定一个类中的对象

时间:2014-10-18 10:16:52

标签: java multithreading methods synchronization locking

我正在尝试学习线程,并考虑以下示例

public class LockExample {
    private Lock lockone = new ReentrantLock();

    public void method1() {
        lockone.lock();
        try {
            // do something
        } finally {
            lockone.unlock();
        } 
    }

    public void method2() {
        lockone.lock();
        try {
            // do something
        } finally {
            lockone.unlock();
        }
    }
}
  1. 这是否意味着如果我们使用相同的锁锁定method1method2,则称线程AB无法访问method1method2同时。但是如果我们使用不同的锁method1method2锁定lockonelocktwo,那么线程A可以访问method1,同时线程B可以访问method2吗?

  2. 为什么我们不单独锁定每个方法而不是将它们放在一个锁中?

  3.  public class LockExample {
         private Lock lockone = new ReentrantLock();
    
             public void method1() {
                 lockone.lock();
                 try {
                     // do something
                 } // wrap the two methods in one lock? 
             }
    
             public void method2() {
    
                 try {
                     // do something
                 } finally {
                     lockone.unlock();
                 }
             }
         }
    }
    

3 个答案:

答案 0 :(得分:1)

  

是否意味着如果我们使用相同的锁来锁定method1和method2,那么说线程A和B不能同时访问method1或method2。但是如果我们使用不同的lockone和locktwo锁定method1和method2,那么threadA可以访问method1,同时线程Bcan访问method2?

是的,如果method1和method2使用相同的锁,则线程A和B不能同时访问method1或方法2。但是如果方法使用不同的锁,那么线程A和B将无法访问相同的方法,但访问不同的方法将起作用。也就是说,线程A和B不能访问相同的方法1或相同的方法2。但是当线程A访问method1时,线程B可以访问method2。

  

为什么我们不单独锁定每个方法而不是将它们放在一个锁中?

如果您希望任何线程阻止方法2访问,直到第一个线程尚未完成对method1和method2的访问/执行,那么给定的代码示例是正确的。

示例:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class Main implements Runnable {
    private Lock lock = new ReentrantLock();

    public void method1() throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + " entered method1.");

        Thread.sleep(1000);

        lock.lock();

        System.out.println(Thread.currentThread().getName() + " ackquired lock.");

        Thread.sleep(1000);
    }

    public void method2() {
        System.out.println(Thread.currentThread().getName() + " entered method2.");

        lock.unlock();

        System.out.println(Thread.currentThread().getName() + " released lock.");
    }

    public void run() {
        try{
            method1();
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            method2();
        }
    }

    public static void main(String [] args) {
        Runnable runnable = new Main();

        new Thread(runnable, "ThreadA").start();
        new Thread(runnable, "ThreadB").start();
    }
}

答案 1 :(得分:0)

如果对两种方法使用相同的锁,那么如果thread-1正在执行方法-1(即,在获取锁之后),则没有其他线程可以执行方法-1以及方法-2。

如果对2种方法使用2个不同的锁,那么如果thread-1和thread-2分别通过获取lock-1和lock-2上的lock来执行method-1和method-2,那么其他线程可以执行方法如果thread-1释放锁,则返回-1;如果thread-2释放锁,则返回method-2。

答案 2 :(得分:0)

  

为什么我们不能,或者我们可以通过仅获取methos1中的锁定并在方法2之后释放锁定来将方法1和2放入一个关键部分?

因为它设计不好。

我工作的办公室有数十万行Java代码需要维护。其中一些已经存在了长达十年之久,开发人员一直都在这个代码中来来往往。坚持严格的风格规则和严格的约定是我们如何保持安全和理智并且大多数没有错误的重要部分。

如果我们使用ReentrantLock,我们会使用始终使用它在第一个示例中使用它的方式:

lockone.lock();
try {
    // do something
} finally {
    lockone.unlock();
} 

如果有一个方法一个,一个方法两个,并且需要以原子方式调用它们,那么我们就这样写:

private methodOne(...) { ... }
private methodTow(...) { ... }
public callMethodOneAndMethodTwo(...) {
    lockOneTwo.lock();
    try {
        methodOne(...);
        methodTwo(...);
    } finally {
        lockOneTwo.unlock();
    }

这种管理锁的方法可以保证在完成锁之后,任何线程都无法解锁锁。它保证任何其他包中的其他函数都不能调用methodOne()而不调用methodTwo()。它保证在没有首先调用methodOne()的情况下,没有这样的函数可以调用methodTwo()。它更容易理解,维护起来也更容易。