使用synchronized(Test2.class)发生奇怪的事情

时间:2017-01-09 10:09:26

标签: java multithreading static java-threads synchronized-block

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();
        }
    }
}

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

1 个答案:

答案 0 :(得分:2)

您的代码开始的所有3个线程都在Test2类上获得相同的锁。当您编写以

开头的方法时
static synchronized

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

foo方法中的synchronized块是多余的。它指定使用相同的类来锁定为使用静态同步。由于内在锁是可重入的,因此不会引起问题。

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

当我跑步时,我得到以下输出:

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

这些线程的运行顺序取决于调度程序。似乎有理由认为Runnable调用t1.foo有一个良好的开端 - 因为它是创建并首先启动它可能有一个窗口,它不会有任何竞争获得锁定。