Java多线程JUC8锁问题

一、线程的8锁问题

前提:8锁问题的讨论是建立在使用Thread.sleep(200)后,假设A线程先于B线程被CPU调度的前提下。

1.1 标准访问,请问先打印邮件还是短信?

class Phone{

    public synchronized void sendEmail() throws Exception{
        System.out.println("----------sendEmail");
    }

    public synchronized void sendSMS() throws Exception{
        System.out.println("----------sendSMS");
    }

}


/**
 * 题目:多线程8锁
 * 1.   标准访问,请问先打印邮件还是短信?
 */
public class Lock8 {

    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(()->{
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"A").start();
  		// 这里使线程先睡眠200毫秒  模拟出A线程先于B线程被CPU调用
        Thread.sleep(200);
        new Thread(()->{
            try {
                phone.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"B").start();


    }
}


  • 如果不加Thread.sleep(200) 则不确定是先打印发邮件还是先发短信,虽然打印邮件比打印短信线程先进入就绪状态,但是cpu调度其顺序不确定。
  • 加了Thread.sleep(200)很大概率先发送邮件再打印短信,200毫秒基本cpu已经调用了线程A

1.2邮件方法暂定4秒钟,请问先打印邮件还是短信?

class Phone{

    public synchronized void sendEmail() throws Exception{
        TimeUnit.SECONDS.sleep(4);
        System.out.println("----------发送邮件");
    }

    public synchronized void sendSMS() throws Exception{
        System.out.println("----------发送短信");
    }

}
...
// Lock8类同上

先发邮件后发短信,sleep只是释放了cpu的调度时间并没有释放锁对象,B线程只有等A线程释放了当前对象锁才能执行。

1.3 新增一个普通方法hello(),请问先打印邮件还是hello?

public class Lock8 {

    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        new Thread(()->{
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"A").start();
        // 这里使线程先睡眠200毫秒  模拟出A线程先于B线程被CPU调用
        Thread.sleep(200);

        new Thread(()->{
            try {
               // phone.sendSMS();
                phone.hello();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"B").start();


    }
}

class Phone{

    public synchronized void sendEmail() throws Exception{
        TimeUnit.SECONDS.sleep(1);
        System.out.println(Thread.currentThread().getName()+"----------发送邮件");
    }

    public synchronized void sendSMS() throws Exception{
        System.out.println(Thread.currentThread().getName()+"----------发送短信");
    }

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

}

B-----------hello
A----------发送邮件

先打印hello在发送邮件

A线程被CPU调度,A发送邮件前睡1秒无释放锁对象即phone对象锁,A线程睡200毫秒后B线程进入就绪态被CPU调度,因为hello方法没有锁,无需获取锁也可执行,所以打印了hello,等到1秒后A线程睡醒打印发送邮件。

1.4两部手机请问先打印邮件还是短信?

public class Lock8 {

    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        Phone phone2 = new Phone();

        new Thread(()->{
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"A").start();
        // 这里使线程先睡眠200毫秒  模拟出A线程先于B线程被CPU调用
        Thread.sleep(200);

        new Thread(()->{
            try {
                phone2.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"B").start();


    }
}

class Phone{

    public synchronized void sendEmail() throws Exception{
        TimeUnit.SECONDS.sleep(1);
        System.out.println(Thread.currentThread().getName()+"----------发送邮件");
    }

    public synchronized void sendSMS() throws Exception{
        System.out.println(Thread.currentThread().getName()+"----------发送短信");
    }

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

}

//输出
//B----------发送短信
//A----------发送邮件

解释:

synchronized是对象锁,A先被CPU调度、发送邮件先睡一秒,此时A线程锁的是phone对象,phone2对象并未上锁。200毫秒后B线程被CPU调度,发送短信。A线程1秒睡醒后发送邮件。

1.5两个静态同步方法,同一部手机,请问先打印邮件还是发送短信?

public class Lock8 {

    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        new Thread(()->{
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"A").start();
        // 这里使线程先睡眠200毫秒  模拟出A线程先于B线程被CPU调用
        Thread.sleep(200);

        new Thread(()->{
            try {
                phone.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"B").start();


    }
}

class Phone{

    public static synchronized void sendEmail() throws Exception{
        TimeUnit.SECONDS.sleep(1);
        System.out.println(Thread.currentThread().getName()+"----------发送邮件");
    }

    public static synchronized void sendSMS() throws Exception{
        System.out.println(Thread.currentThread().getName()+"----------发送短信");
    }


}

A----------发送邮件
B----------发送短信

A线程被CPU调度,发送邮件前睡1秒,因为加了statics所以此时睡的时候锁的是类模板,这里也就是Phone,200毫秒后B线程被CPU调度,此时因为Phone类上锁了所以等待,1秒后A线程睡醒发送邮件释放Phone类锁,然后B线程再发送短信

1.6 两个静态同步方法,2部手机,请问先打印邮件还是发送短信?

public class Lock8 {

    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        Phone phone2 = new Phone();

        new Thread(()->{
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"A").start();
        // 这里使线程先睡眠200毫秒  模拟出A线程先于B线程被CPU调用
        Thread.sleep(200);

        new Thread(()->{
            try {
                phone2.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"B").start();


    }
}

class Phone{

    public static synchronized void sendEmail() throws Exception{
        TimeUnit.SECONDS.sleep(1);
        System.out.println(Thread.currentThread().getName()+"----------发送邮件");
    }

    public static synchronized void sendSMS() throws Exception{
        System.out.println(Thread.currentThread().getName()+"----------发送短信");
    }

}

A----------发送邮件
B----------发送短信

phone和phone2的类模板都是Phone,线程A被CPU调度后,发送邮件前睡1秒锁上类模板,200毫秒后B线程进入就绪态开始被CPU调度,但是Phone类模板被锁,所以B线程只有等A线程释放类模板锁。

1.7 1个普通同步方法,1个静态同步方法,1部手机,请问先打印邮件还是短信?

public class Lock8 {

    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        new Thread(()->{
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"A").start();
        // 这里使线程先睡眠200毫秒  模拟出A线程先于B线程被CPU调用
        Thread.sleep(200);

        new Thread(()->{
            try {
                phone.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"B").start();


    }
}

class Phone{

    public static synchronized void sendEmail() throws Exception{
        TimeUnit.SECONDS.sleep(1);
        System.out.println(Thread.currentThread().getName()+"----------发送邮件");
    }

    public synchronized void sendSMS() throws Exception{
        System.out.println(Thread.currentThread().getName()+"----------发送短信");
    }

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

}

B----------发送短信
A----------发送邮件

类模板锁和具体的对象锁无关

A线程被调度,发送邮件前睡1秒锁住创建类的类模板,200毫秒后B线程被调度,因为B发送短信的方法是具体对象的,而且类模板锁和具体的对象锁又无关所以此时可以发送短信,然后A线程睡1秒后继续执行。

1.8 1个普通同步方法,1个静态同步方法,2部手机,请问先打印邮件还是短信?

public class Lock8 {

    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        Phone phone2 = new Phone();

        new Thread(()->{
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"A").start();
        // 这里使线程先睡眠200毫秒  模拟出A线程先于B线程被CPU调用
        Thread.sleep(200);

        new Thread(()->{
            try {
                phone2.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"B").start();


    }
}

class Phone{

    public static synchronized void sendEmail() throws Exception{
        TimeUnit.SECONDS.sleep(1);
        System.out.println(Thread.currentThread().getName()+"----------发送邮件");
    }

    public synchronized void sendSMS() throws Exception{
        System.out.println(Thread.currentThread().getName()+"----------发送短信");
    }

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

}

B----------发送短信
A----------发送邮件

原因同1.7.1

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值