当前位置: 首页 > 知识库问答 >
问题:

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

公孙宏远
2023-03-14

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

在foo()方法中有一个synchronized块,它被锁定在调用对象上。由于这是一个实例级的锁定,这两个方法应该同时开始执行,因为它们是从两个独立的实例调用的。但是,他们被顺序执行。

这是因为,两个实例都是从同一个线程主调用的吗?

预期输出(应并行执行)

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) {}
        }
    }

}

共有1个答案

公良鸿光
2023-03-14

在启动线程之前,您开始同步运行a1,当然,您将在主线程上获得a1的输出,因为在a1完成之前,它将无法到达thread start语句。

在主线程上运行A1之前,尝试先启动线程运行A2,看看会得到什么。

您还应该意识到线程调度可能会延迟,并且调用thread#start不会立即在单独的线程上开始执行,而是将其排队等待系统线程调度程序。您可能还需要考虑使用同步设备,例如CyclicBarrier,以便在运行A2的线程和运行A1的主线程之间进行协调,否则,即使您似乎是在A2之前启动线程运行A1,也可能会得到完全相同的结果。

 类似资料:
  • 尝试可视化和理解同步。 对同步块使用静态锁定对象(代码a)和非静态锁定对象(代码B)之间有什么区别 它在实际应用中有什么不同 一方会有哪些陷阱而另一方不会 确定使用哪一个的标准是什么 代码A 代码B 笔记 上面的代码显示了构造函数,但是您可以讨论静态方法和非静态方法中的行为是如何不同的。另外,在同步块修改静态成员变量时使用静态锁是否有利? 我已经看过了这个问题的答案,但是还不清楚不同的使用场景是什

  • 我有点困惑。请看看下面的代码。 我确信调用此序列是可能的。 虽然我仍然有一个小小的困惑,但我们可以很容易地看到也调用方法,这是一个静态方法。方法 是调用非同步静态方法的静态同步方法。当 thread-2 获得类级锁时,为什么从 Thread-1 调用 没有被阻止? 我只是在逻辑上感到困惑,如果一个线程获得类级锁定,则该类其他非同步静态方法保持打开状态,以便从其他方法(实例方法)调用。为什么?

  • 问题内容: 任何人都可以解释以下语句吗……“静态同步方法和非静态同步方法不会互相阻塞-它们可以同时运行” 问题答案: 锁定对象在静态方法和非静态方法上有所不同。静态方法将Class对象用作锁(锁obj:),而非静态方法将实例对象用作锁,此时方法的调用已绑定到该对象(锁obj:)。

  • 本文向大家介绍java synchronized同步静态方法和同步非静态方法的异同,包括了java synchronized同步静态方法和同步非静态方法的异同的使用技巧和注意事项,需要的朋友参考一下 java synchronized 详解 synchronized关键字有两种用法,一种是只用于方法的定义中,另外一种是synchronized块,我们不仅可以使用synchronized来同步一个对

  • 问题内容: Java教程说:“不可能在同一对象上两次调用同步方法。” 这对于静态方法意味着什么?由于静态方法没有关联的对象,所以synced关键字会锁定在类而不是对象上吗? 问题答案: 由于静态方法没有关联的对象, 所以synced关键字会锁定在类而不是对象上吗? 是。

  • 我了解Class对象上的静态同步锁,以及Object实例上的非静态锁。 但是,在此问题的可接受答案中:同步块中的静态与非静态锁定对象 使用非静态锁定对象时: 线程1调用o1.foo() 线程2调用o1.foo(),将不得不等待线程1完成 线程3调用o2.foo(),它可以只继续,不介意线程1和2 为什么线程 3 可以继续而不考虑线程 1 和 2。线程 3 是否必须等待从线程 1 或 2 获取对象实