JUC之8锁

219 阅读3分钟

模拟一个手机类(资源),现在有发邮件和发短信两个功能。两个线程取操作这个资源类,是先发邮件还是先发短信。

一锁:标准访问代码 ,先打印邮件还是短信

class Phone{
    public synchronized void sendEmail(){
        System.out.println(Thread.currentThread().getName() + ":sendEmail");
    }

    public synchronized void sendSMS(){
        System.out.println(Thread.currentThread().getName() + ":sendSMS");
    }
}

public class EightLockDemo {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(()->{
            phone.sendEmail();
        },"A").start();
        
		Thread.sleep(100);
        
        new Thread(()->{
            phone.sendSMS();
        },"B").start();
    }
}

结果:

image-20200819133748591

解析:

两个线程各自去找各自需要的资源,他们需要的资源都使用着同一把锁,所以只有一个线程可以先获得资源的执行权,另一个线程则需要等待上一个线程执行完毕才能执行。

二锁:邮件方法暂定4秒,先打印邮件还是短信

class Phone{
    public synchronized void sendEmail(){
        try {
            TimeUnit.SECONDS.sleep(4);
            System.out.println(Thread.currentThread().getName() + ":sendEmail");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void sendSMS(){
        System.out.println(Thread.currentThread().getName() + ":sendSMS");
    }
}

public class EightLockDemo {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(()->{
            phone.sendEmail();
        },"A").start();
        
		Thread.sleep(100);
        
        new Thread(()->{
            phone.sendSMS();
        },"B").start();
    }
}

结果

image-20200819134635106

解析:

和一锁道理相同,因为使用的是一把锁,而且邮件方法使用的sleep方法不会释放锁,所以线程B需要等线程A唤醒后执行完毕后才能执行。

三锁:新增一个普通方法hello,先打印邮件还是hello

class Phone{
    public synchronized void sendEmail(){
        try {
            TimeUnit.SECONDS.sleep(4);
            System.out.println(Thread.currentThread().getName() + ":sendEmail");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void hello(){
        System.out.println(Thread.currentThread().getName() + ":hello");
    }
}

public class EightLockDemo {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        new Thread(()->{
            phone.sendEmail();
        },"A").start();

        Thread.sleep(100);

        new Thread(()->{
            phone.hello();
        },"B").start();
    }
}

结果

image-20200819134947025

解析:

hello方法没有加同步,所以不受锁的影响。

四锁:两个手机对象,A线程打印第一部手机的邮件,B打印第二部手机的短信,先打印邮件还是短信

class Phone{
    public synchronized void sendEmail(){
        try {
            TimeUnit.SECONDS.sleep(4);
            System.out.println(Thread.currentThread().getName() + ":sendEmail");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void sendSMS(){
        System.out.println(Thread.currentThread().getName() + ":sendSMS");
    }
}

public class EightLockDemo {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        Phone phone2 = new Phone();
        new Thread(()->{
            phone.sendEmail();
        },"A").start();

        Thread.sleep(100);

        new Thread(()->{
            phone2.sendSMS();
        },"B").start();
    }
}

结果:

image-20200819135222563

解析:

两个对象使用的是两把锁,所以互不干扰。

五锁:两个静态同步方法,同一个手机对象,先打印邮件还是短信

class Phone{
    public static synchronized void sendEmail(){
        try {
            TimeUnit.SECONDS.sleep(4);
            System.out.println(Thread.currentThread().getName() + ":sendEmail");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static synchronized void sendSMS(){
        System.out.println(Thread.currentThread().getName() + ":sendSMS");
    }

}

public class EightLockDemo {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        new Thread(()->{
            phone.sendEmail();
        },"A").start();

        Thread.sleep(100);

        new Thread(()->{
            phone.sendSMS();
        },"B").start();
    }
}

结果:

image-20200819135604396

解析:

和第二锁相同,只是加了静态方法,但是还是共用一把锁

六锁:两个静态同步方法,两个手机对象,A线程打印第一部手机的邮件,B打印第二部手机的短信,先打印邮件还是短信

class Phone{
    public static synchronized void sendEmail(){
        try {
            TimeUnit.SECONDS.sleep(4);
            System.out.println(Thread.currentThread().getName() + ":sendEmail");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static synchronized void sendSMS(){
        System.out.println(Thread.currentThread().getName() + ":sendSMS");
    }

}

public class EightLockDemo {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        Phone phone2 = new Phone();
        new Thread(()->{
            phone.sendEmail();
        },"A").start();

        Thread.sleep(100);

        new Thread(()->{
            phone2.sendSMS();
        },"B").start();
    }
}

image-20200819140201497

解析:

静态方法的作用范围是从这个类的唯一的字节码文件开始的,相当于把这个手机模板中的方法上锁了,这样以来不管多少对象都是用的这个模板中上了锁的方法。

七锁:一个普通同步方法,一个静态同步方法,一个手机对象,先打印邮件还是短信

class Phone{
    public static synchronized void sendEmail(){
        try {
            TimeUnit.SECONDS.sleep(4);
            System.out.println(Thread.currentThread().getName() + ":sendEmail");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void sendSMS(){
        System.out.println(Thread.currentThread().getName() + ":sendSMS");
    }

}

public class EightLockDemo {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        new Thread(()->{
            phone.sendEmail();
        },"A").start();

        Thread.sleep(100);

        new Thread(()->{
            phone.sendSMS();
        },"B").start();
    }
}

结果:

image-20200819140404274

解析:

静态方法锁的是字节码中的方法,这是一把锁,然后普通同步方法用的当前类的对象做锁,这又是一把锁,两个方法没有使用同一把锁,所以互不影响。两个锁分别是(class的锁,this的锁)

八锁:一个普通同步方法,一个静态同步方法,两个手机对象,先打印邮件还是短信

class Phone{
    public static synchronized void sendEmail(){
        try {
            TimeUnit.SECONDS.sleep(4);
            System.out.println(Thread.currentThread().getName() + ":sendEmail");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void sendSMS(){
        System.out.println(Thread.currentThread().getName() + ":sendSMS");
    }

}

public class EightLockDemo {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        Phone phone2 = new Phone();
        new Thread(()->{
            phone.sendEmail();
        },"A").start();

        Thread.sleep(100);

        new Thread(()->{
            phone2.sendSMS();
        },"B").start();
    }
}

结果:

image-20200819140521054

解析:

和七锁相同,虽然变成两个对象了,但是还是两把不同的锁,互不影响。