多线程8锁问题

多线程8锁问题

在多线程环境中,访问资源类的顺序到底是如何?
最近,在网络上看到一道题目,通过多线程的8种锁情况了解访问资源类的顺序。


  1. 标准访问,先打印邮件方法还是短信方法?
class Phone{
    public synchronized void sendEmail(){
        System.out.println("----sendEmail----");
    }
    public synchronized void sendSMS(){
        System.out.println("----sendSMS----");
    }
}
public class lock8 {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        new Thread(() -> {
            phone.sendEmail();
        }, "A").start();
        //睡眠4毫秒
        TimeUnit.MILLISECONDS.sleep(4);
        new Thread(() -> {
            phone.sendSMS();
        }, "B").start();
    }
}

运行结果:

synchronized关键字锁的不是当前方法,而是该方法所在的整个资源类,也就是说,同一时间下,只能有一个线程进入当前的资源类访问同步方法,所以运行结果跟方法调用的顺序相同。


  1. 邮件方法暂停4秒,先打印邮件方法还是短信方法?
class Phone {
    public synchronized void sendEmail() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("----sendEmail----");
    }
    public synchronized void sendSMS(){
        System.out.println("----sendSMS----");
    }
}

运行结果:

第二锁的原理跟第一锁相同,只不过是在发邮件方法中线程睡眠了4秒,当线程A访问发邮件方法睡眠时,线程B无法进入该资源类,所以运行结果还是相同。


  1. 新增一个普通方法hello,先打印邮件方法还是短信方法?
class Phone {
    public synchronized void sendEmail() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("----sendEmail----");
    }
    public void hello(){
        System.out.println("----hello----");
    }
}
public class lock8 {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        new Thread(() -> {
            phone.sendEmail();
        }, "A").start();
        TimeUnit.MILLISECONDS.sleep(4);
        new Thread(() -> {
            phone.hello();
        }, "B").start();
    }
}

运行结果:

新增的hello方法并没有被synchronized关键字修饰,不是同步方法,所以在线程A访问发邮件方法时,线程B可以访问到hello方法,而线程A需要睡眠4秒,所以运行结果是hello先。


  1. 两个资源类,先打印邮件方法还是短信方法?
class Phone {
    public synchronized void sendEmail() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("----sendEmail----");
    }
    public synchronized void sendSMS(){
        System.out.println("----sendSMS----");
    }
}
public class lock8 {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        Phone phone2 = new Phone();
        
        new Thread(() -> {
            phone.sendEmail();
        }, "A").start();
        TimeUnit.MILLISECONDS.sleep(4);
        new Thread(() -> {
            phone2.sendSMS();
        }, "B").start();
    }
}

运行结果:

第四锁中创建了两个资源类,main方法中访问的是两个不同资源类的方法,相互并不干扰,而发邮件的方法睡眠4秒,所以发短信的方法会先打印。

  1. 两个静态同步方法,同一个资源类,先打印邮件方法还是短信方法?
class Phone {
    public static synchronized void sendEmail() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("----sendEmail----");
    }
    public static synchronized void sendSMS(){
        System.out.println("----sendSMS----");
    }
}
public class lock8 {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();

        new Thread(() -> {
            phone.sendEmail();
        }, "A").start();
        TimeUnit.MILLISECONDS.sleep(4);
        new Thread(() -> {
            phone.sendSMS();
        }, "B").start();
    }
}

运行结果:

这题涉及到static静态,锁的不再是这个资源类对象,锁的是这个对象在类加载器中的类模板(.class),但由于还是同一个资源类,所以的顺序原理还是跟第一锁差不多。

  1. 两个静态同步方法,两个资源类,先打印邮件方法还是短信方法?
class Phone {
    public static synchronized void sendEmail() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("----sendEmail----");
    }
    public static synchronized void sendSMS(){
        System.out.println("----sendSMS----");
    }
}
public class lock8 {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        Phone phone2 = new Phone();

        new Thread(() -> {
            phone.sendEmail();
        }, "A").start();
        TimeUnit.MILLISECONDS.sleep(4);
        new Thread(() -> {
            phone2.sendSMS();
        }, "B").start();
    }
}

运行结果:

第六锁变换成两个资源类,但由于static锁的是整个类的类模板(.class),所以不论实例化多少个资源类访问的结果还是相同的。

  1. 一个同步方法,一个静态同步方法,一个资源类,先打印邮件方法还是短信方法?
class Phone {
    public static synchronized void sendEmail() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("----sendEmail----");
    }
    public synchronized void sendSMS(){
        System.out.println("----sendSMS----");
    }
}
public class lock8 {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();

        new Thread(() -> {
            phone.sendEmail();
        }, "A").start();
        TimeUnit.MILLISECONDS.sleep(4);
        new Thread(() -> {
            phone.sendSMS();
        }, "B").start();
    }
}

运行结果:

第七锁,一个静态同步方法,一个普通同步方法,一个锁的是整个类模板,一个锁的是当前对象,两者相互不冲突,所以发短信先显示,发邮件的需要睡眠4秒才显示。

  1. 一个同步方法,一个静态同步方法,两个资源类,先打印邮件方法还是短信方法?
class Phone {
    public static synchronized void sendEmail() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("----sendEmail----");
    }
    public synchronized void sendSMS(){
        System.out.println("----sendSMS----");
    }
}
public class lock8 {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        Phone phone2 = new Phone();

        new Thread(() -> {
            phone.sendEmail();
        }, "A").start();
        TimeUnit.MILLISECONDS.sleep(4);
        new Thread(() -> {
            phone2.sendSMS();
        }, "B").start();
    }
}

运行结果:

第八锁与第七锁的原理类似。

总结

synchronized实现同步的基础:Java中的每个对象都可以作为锁。
具体表现为以下三种形式:

  • 对于普通同步方法,锁的是当前实例对象
  • 对于静态同步方法,锁的是当前类的Class对象
  • 对于同步方法快,锁的是synchronized括号里配置的对象
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值