1
public class Test2 {
    static int count;
    public static void main(String[] args) {
        final Test2 t1 = new Test2();
        final Test2 t2 = new Test2();

        new Thread(new Runnable() {

            @Override
            public void run() {
                t1.foo();
            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                t1.bar();
            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                t2.foo();
            }
        }).start();
    }
    public static synchronized void foo() {
        synchronized (Test2.class) {
            System.out.println("run bar"+count++);
            try {
                Thread.sleep(100000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    public static synchronized void bar() {
        System.out.println("run bar");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

以上是我尝试过的代码。当我在一个同步的类(Test2.class)中编写所有代码时,我发现发生了一些奇怪的事情。调用 foo() 方法后,我无法立即调用 bar() 方法。我认为它锁定了同一个对象。如何解释这个奇怪的事情。

4

1 回答 1

2

您的代码启动的所有 3 个线程都在 Test2 类上获取相同的锁。当你编写一个以

static synchronized

这意味着它必须获取类对象的锁。

foo 方法中的同步块是多余的。它指定使用与使用静态同步相同的类来锁定。由于内在锁是可重入的,这不会导致问题。

无论如何,您的每个线程都获取锁,运行完成,然后释放锁。由于您锁定的是类而不是实例,因此线程使用哪个 Test2 实例并不重要,它们仍然获得相同的锁并一次执行一个。

当我运行它时,我得到以下输出:

c:\Users\ndh>java Test2
run bar0
run bar1
run bar

这些线程的运行顺序取决于调度程序。猜测调用 t1.foo 的 Runnable 抢占先机似乎是合理的——因为它是首先创建和启动的,它可能有一个窗口,它不会有任何竞争获取锁。

于 2017-01-09T11:50:04.377 回答