为什么同步锁定另一种方法?

时间:2014-11-14 07:09:42

标签: java multithreading

我是java中的多线程的新手。我编写了一些类来测试synchronized的函数。我有一些使用synchronized的方法:

    public class ShareUtil {
        private static Queue<Integer> queue = new LinkedList<Integer>();
        public static synchronized void do1(){
            System.out.println("do1");
            sleep();
        }
        public static synchronized void do2(){
            System.out.println("do2");
            sleep();
        }
        private static void sleep(){
            try {
                Thread.sleep(1000*50000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
}

你可以看到有两种方法使用synchronized,我运行两个线程分别使用这两种方法。

class Run1 implements Runnable{

    @Override
    public void run() {
        // TODO Auto-generated method stub
        ShareUtil.do1();
    }

}
class Run2 implements Runnable{

    @Override
    public void run() {
        // TODO Auto-generated method stub
        ShareUtil.do2();
    }

}
public class DoMain {
    public static void main(String[] args) {
        ExecutorService pools = Executors.newCachedThreadPool();
        for(int i=0;i<10;i++){
            pools.execute(new Run1());
            pools.execute(new Run2());
        }
        pools.shutdown();
    }
}

但是,它只是打印“do1”而不是打印“do2”。​​我想知道为什么?“同步”使用方法的关键是使方法只有一个线程同时使用,但为什么要锁定其他方法?

4 个答案:

答案 0 :(得分:5)

重要的关键是 synchronized锁定对象,而不是方法。

根据https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

  

每个对象都有一个与之关联的内在锁。按照惯例,   需要对对象进行独占和一致访问的线程   字段必须在访问之前获取对象的内部锁   它们,然后在它们完成后释放内在锁。一个   据说线程拥有它之间的内在锁定   获得了锁并释放了锁。 只要一个帖子拥有一个   内在锁,没有其他线程可以获得相同的锁。另一个   线程在尝试获取锁时会阻塞。

所以,ShareUtil的类内在锁(你的方法是static,所以这是 intrinsic lock for the Class object associated with the class)当线程T1执行do1()被锁定>,除非T1释放它,否则没有其他线程可以获得此锁。

您调用的方法sleep()不会释放此锁定,而如果您调用wait(),则会检查Difference between wait() and sleep()。这就是为什么当另一个线程T2尝试访问do2()时,它必须等待T1的do1()完成(内部锁被释放)。

答案 1 :(得分:1)

因为当您同步static方法时,它会获取Class对象上的锁定。一旦线程锁定Class对象,其他任何线程都不能进入同一类的另一个static方法。

当线程在锁定时调用sleep()时,其他任何线程都无法访问其他静态方法,因为该线程不会失去锁的所有权。

因此sleep()仅导致任一线程执行其方法。您有时也可以do2打印,但不能do1

答案 2 :(得分:0)

Run1()首先获取类ShareUtil上的锁,然后是Run2(),它被阻塞直到Run1()释放锁。一旦Run2()获得锁定,它将打印do2()。同步键保证只有一个线程通过获取类上的锁定来访问该方法(如果方法是静态的)或“object”(如果方法是实例的话)。

答案 3 :(得分:0)

我将代码Thread.sleep(1000*50000);更改为Thread.sleep(1000*2); 输出结果是不规则的。

do2
do1
do1
do1
do1
do1
do1
do1
do1
do2
do2
do2
do2
do2
do2
do2
do2
do2
do1

我们可以看到这些线程正在等待ShareUtil.class的锁定,并且锁定在Thread.sleep之后被重新定位,其中一个等待的线程将获取锁定并转向运行。

相关问题