代码之家  ›  专栏  ›  技术社区  ›  somnathchakrabarti

在非静态方法中使用同步块锁定实例

  •  0
  • somnathchakrabarti  · 技术社区  · 6 年前

    按照下面的代码,我有两个类A的实例-a1和a2。并分别对两个实例调用foo()方法。

    foo()方法中有一个同步块,它被锁定在调用对象上。因为这是一个实例级锁定,所以这两个方法应该同时开始执行,因为它们是从两个不同的实例调用的。但是,他们是按顺序被处决的。

    我的理解是“this”指的是调用Runnable实例,它是不同的,甚至线程也是不同的。因此,Thread.sleep不应该阻塞另一个线程。那么,为什么run的两个调用没有并行发生呢?

    main <time> Inside A.run
    Thread-0 <time> Inside A.run
    Thread-0 <time+4s> Exiting A.run
    main <time+5s> Exiting A.run
    

    实际输出(按顺序执行)

    main <time> Inside A.run
    main <time+5s> Exiting A.run
    Thread-0 <time+5s> Inside A.run
    Thread-0 <time+9s> Exiting A.run 
    

    import java.time.*;
    import java.time.format.DateTimeFormatter;
    
    public class Test {
    
        public static void main(String[] args) {
            /*A a1 = new A(5000); A a2 = new A(4000);
            a1.foo(); a2.foo();*/
            A a1 = new A(5000); A a2 = new A(4000);
            Thread t = new Thread(a2);
            /*a1.run(); t.start();*/
            t.start(); a1.run(); // <-- putting t.start() before a1.run() solves the issue
        }
    
    }
    
    class A implements Runnable {
        public long waitTime;
        public A() {}
        public A(long timeInMs) {
            waitTime = timeInMs;
        }
        public void run() {
            synchronized(this) {
                try {
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
                    LocalDateTime time = LocalDateTime.now();
                    System.out.println(Thread.currentThread().getName() + " " + formatter.format(time) + " Inside A.run");
                    Thread.sleep(waitTime);
                    time = LocalDateTime.now();
                    System.out.println(Thread.currentThread().getName() + " " + formatter.format(time) + " Exiting A.run");
                } catch (InterruptedException e) {}
            }
        }
    
    }
    
    2 回复  |  直到 6 年前
        1
  •  1
  •   user2982130 user2982130    6 年前

    a1

    尝试启动线程运行 a2 在主线上,看看你得到了什么。

    您还应该知道线程调度可能会延迟,并且调用 Thread#start CyclicBarrier 为了协调线程运行 主线程正在运行 a1级 ,否则你可以 仍然 即使看起来您正在启动线程运行,也会得到完全相同的结果 之前 a2级

        2
  •  1
  •   John H    6 年前

    是因为两个实例都从同一个

    对。调用Thread.sleep()是同步的,除非被中断,否则将在一段时间内阻止当前线程。您直接调用a1.foo(),它将在持续时间内阻塞主线程,这就是您看到的结果。创建单独的线程并在每个线程中调用foo(),您将看到预期的行为。