Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/355.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
一个类中的Java锁对象_Java_Multithreading_Methods_Synchronization_Locking - Fatal编程技术网

一个类中的Java锁对象

一个类中的Java锁对象,java,multithreading,methods,synchronization,locking,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 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();
        }
    }
}
  • 这是否意味着如果我们使用相同的锁锁定
    method1
    method2
    ,那么线程
    A
    B
    不能同时访问
    method1
    method2
    。但是如果我们使用不同的锁来锁定
    method1
    method2
    ,那么线程
    A
    可以访问
    method1
    ,同时线程
    B
    可以访问
    method2

  • 为什么我们不分别锁定每个方法,而不是将它们放在一个锁中


  • 如果对这两个方法使用相同的锁,那么如果线程1正在执行方法1(即,在获取锁之后),那么没有其他线程可以像方法2那样执行方法1

    如果对2个方法使用2个不同的锁,那么如果线程1和线程2分别通过获取lock-1和lock-2上的锁来执行方法1和方法2,那么其他线程可以在线程1释放锁时执行方法1,在线程2释放锁时执行方法2

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

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

    为什么我们不分别锁定每个方法,而不是将它们放在一个锁中

    如果您想让任何线程阻止方法2的访问,直到第一个线程还没有完成方法1和方法2的访问/执行,那么给定的代码示例是正确的

    例如:

    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();
        }
    }
    
    为什么我们不能,或者我们可以通过在method1中获取锁,然后在method2之后释放锁,将method1和method2变成一个关键部分

    因为这是个糟糕的设计

    我工作的办公室有数十万行Java代码需要维护。其中一些已经存在了十年之久,开发人员一直在来来往往地使用这些代码。遵守严格的风格规则和严格的惯例是我们如何保持一切安全、理智和基本上没有bug的重要组成部分

    如果我们使用ReentrantLock,我们总是按照您在第一个示例中使用它的方式使用它:

    lockone.lock();
    try {
        // do something
    } finally {
        lockone.unlock();
    } 
    
    如果有一个methodOne和methodTwo,并且需要在原子上调用它们,那么我们这样写:

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

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

    您发布的第二段代码没有意义。例如,如果一个线程调用
    method2
    而不持有锁(即以前没有调用
    method1
    ),则会抛出
    IllegalMonitorStateException
    。@CristianGreco-我想OP是在试图解释他的逻辑,而不是实际代码:)也许这对您来说是显而易见的,但以防万一不是这样:LockExample类的每个实例都有自己单独的ReentrantLock对象。因此,如果有两个LockExample对象a和b,则一个线程可能位于a.method1()中,而另一个线程位于b.method2()中。再一次,如果这是显而易见的,我很抱歉,但这似乎是一个很多初学者不容易理解的想法。谢谢!但是为什么我们不能,或者我们可以通过在method1中获取锁,然后在method2之后释放锁,将method1和method2变成一个关键部分呢?对不起,我看不出这有什么问题…@stillAFanOfTheSimpsons-不,我们不能这么做。同步建立了“先发生后发生”关系。实际上,当JVM将执行指令时,它可以在同步块内或同步块(或方法)外重新排序指令,但不能在同步块之间重新排序,以提高性能。在这种情况下,任何线程都可以只调用method2,而不调用method1。在第二种情况下,任何线程都必须首先调用method1,然后调用method2。否则将抛出非法监视异常。
    private methodOne(...) { ... }
    private methodTow(...) { ... }
    public callMethodOneAndMethodTwo(...) {
        lockOneTwo.lock();
        try {
            methodOne(...);
            methodTwo(...);
        } finally {
            lockOneTwo.unlock();
        }