[英]Why does the synchronized lock another method?
我是java多线程的新手,我编写了一些类来测试synced的功能。我有一些使用synced的方法:
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();
}
}
}
您可以看到有两种使用同步的方法,并且我运行两个线程分别使用这两种方法。
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”。我想知道为什么吗?使用“ synchronized”键的方法使该方法只能同时使用一个线程,但是为什么要锁定其他方法呢?
重要的键是synchronized
锁对象,而不是方法。
根据https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html
每个对象都有一个与之关联的固有锁。 按照约定,需要对对象的字段进行独占且一致的访问的线程必须在访问对象之前先获取对象的固有锁,然后在完成对它们的锁定后释放固有锁。 据称,线程在获取锁和释放锁之间拥有内部锁。 只要一个线程拥有一个内在锁,其他任何线程都无法获得相同的锁。 另一个线程在尝试获取锁时将阻塞。
因此, 当线程T1执行do1()时 , ShareUtil的类固有锁定(您的方法是static
,所以这是与该类关联的Class对象的固有锁定 ) 被锁定 ,除非T1释放,否则其他线程都无法获得此锁定。它。
而且您调用的sleep()
方法不会释放此锁,而如果调用wait()
则会释放此锁,请检查wait()和sleep()之间的区别 。 这就是为什么当另一个线程T2尝试访问do2()时,它必须等待T1的do1()完成(释放内部锁)的原因。
因为当您同步static
方法时,它会获得对Class
对象的锁定。 一旦线程在Class
对象上锁定,其他任何线程都不能输入同一类的另一个static
方法。
当您在具有锁的线程上调用sleep()
时,其他线程都无法访问其他静态方法,因为该线程不会丢失锁的所有权。
因此, sleep()
仅导致其中一个线程执行其方法。 您还可以得到有时do2
打印,但不do1
。
Run1()首先启动,获取对类ShareUtil的锁定,其后是Run2(),直到Run1()释放该锁定为止,Run2()才被锁定。 一旦Run2()获得锁,它将打印do2()。 如果方法是静态的,则同步密钥通过获取对类的锁定来确保只有一个线程访问该方法;如果方法是实例,则通过“对象”来确保。
我更改代码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
之后重新获得该锁,其中一个正在等待的线程将抓住该锁并开始运行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.