JUC八锁现象

711 阅读2分钟

8锁现象,实际对应的就是8个问题 掌握了这8个问题后:可以清楚判断锁的是谁

1.多个线程使用同一把锁

import java.util.concurrent.TimeUnit;

public class lock1 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(()->{
            phone.sendemail();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone.call();
        },"B").start();
    }

}
class Phone{
    public synchronized void sendemail(){
        System.out.println("sendemail");
    }
    public synchronized void call(){
        System.out.println("call");
    }
}

此时synchronized 锁的对象是方法的调用者(phone),这两个方法共用同一个锁,谁先拿到谁执行

由执行sendemail的线程先拿到锁,所以先执行

image.png

2.多个线程使用同一把锁,其中某个线程里面还有阻塞

import java.util.concurrent.TimeUnit;

public class lock2 {
    public static void main(String[] args) {
        Phone2 phone = new Phone2();
        new Thread(()->{
            phone.sendemail();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone.hello();
        },"B").start();
    }

}
class Phone2{
    public synchronized void sendemail(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sendemail");
    }
    public synchronized void call(){
        System.out.println("call");
    }
}

先拿到锁的先执行,即使在某方法中设置了阻塞

  1. phone对象,就是方法的调用者,它可以打电话和发短信
  2. 现在有两个人线程A 和 线程B,他们一个想打电话,一个想发短信
  3. 线程A,先拿到锁,抱着锁睡了4秒
  4. 线程B肯定拿不到锁,需要等待线程A执行完

image.png

3.多个线程有锁与没锁

import java.util.concurrent.TimeUnit;

public class lock3 {
    public static void main(String[] args) {
        Phone3 phone1 = new Phone3();
        new Thread(()->{
            phone1.sendemail();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone1.hello();
        },"B").start();
    }

}
class Phone3{
    public synchronized void sendemail(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sendemail");
    }
    public void hello(){
        System.out.println("hello");
    }
}

有的线程有锁,有的线程没锁,两者之间不存在竞争同一把锁的情况,先后执行顺序是随机的

但是由于A线程休眠了一秒,所以会先执行B线程

image.png

4.多个线程使用多把锁

import java.util.concurrent.TimeUnit;

public class lock4 {
    public static void main(String[] args) {
        Phone4 phone1 = new Phone4();
        Phone4 phone2 = new Phone4();
        new Thread(()->{
            phone1.sendemail();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone2.call();
        },"B").start();
    }

}
class Phone4{
    public synchronized void sendemail(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sendemail");
    }
    public synchronized void call(){
        System.out.println("call");
    }
}

调用者不同,它们之间用的不是同一个锁,A获取锁后休眠一秒,B先出现执行结果

image.png

5.锁class模板

import java.util.concurrent.TimeUnit;

public class lock5 {
    public static void main(String[] args) {
        new Thread(()->{
            Phone5.sendemail();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            Phone5.call();
        },"B").start();
    }

}
class Phone5{
    public static synchronized void sendemail(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sendemail");
    }
    public static synchronized void call(){
        System.out.println("call");
    }
}

因为锁的是class模板,而这个模板是唯一的一个,所以无论几个对象,使用的锁都是一样

image.png

6.锁方法的调用者和锁class模板

import java.util.concurrent.TimeUnit;

public class lock6 {
    public static void main(String[] args) {
        Phone6 people = new Phone6();
        new Thread(()->{
            Phone6.sendemail();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            people.call();
        },"B").start();
    }

}
class Phone6{
    public static synchronized void sendemail(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sendemail");
    }
    public synchronized void call(){
        System.out.println("call");
    }
}

两个锁的东西是不同,一个锁的是class模板,一个锁的是方法调用者,两个都是互不影响

image.png