Java多线程之八锁问题

1 八锁现象

  • 问题一:标准访问,先打印短信还是邮件?
public class Lock_8_1 {
    public static void main(String[] args) throws Exception {
        Phone phone = new Phone();
        new Thread(() -> { phone.sendSMS(); }, "AA").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(() -> { phone.sendEmail(); }, "BB").start();
    }
}

class Phone {
    public synchronized void sendSMS() {
        System.out.println("------sendSMS");
    }
    public synchronized void sendEmail() {
        System.out.println("------sendEmail");
    }
    public void getHello() {
        System.out.println("------getHello");
    }
}/*sendSMS*/
  • 问题二:停4秒在短信方法内,先打印短信还是邮件?
public class Lock_8_2 {
    public static void main(String[] args) throws Exception {
        Phone phone = new Phone();
        new Thread(() -> { phone.sendSMS(); }, "AA").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(() -> { phone.sendEmail(); }, "BB").start();
    }
}

class Phone {
    public synchronized void sendSMS() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("------sendSMS");
    }
    public synchronized void sendEmail() {
        System.out.println("------sendEmail");
    }
}/*sendSMS*/
  • 问题三:新增普通的getHello方法,是先打印短信还是hello?
public class Lock_8_3 {
    public static void main(String[] args) throws Exception {
        Phone phone = new Phone();
        new Thread(() -> { phone.sendSMS(); }, "AA").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(() -> { phone.getHello(); }, "BB").start();
    }
}

class Phone {
    public synchronized void sendSMS() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("------sendSMS");
    }
    public synchronized void sendEmail() {
        System.out.println("------sendEmail");
    }
    public void getHello() {
        System.out.println("------getHello");
    }
}/*getHello*/
  • 问题四:现在有两部手机,先打印短信还是邮件?
public class Lock_8_4 {
    public static void main(String[] args) throws Exception {
        Phone phone1 = new Phone();
        Phone phone2 = new Phone();
        new Thread(() -> { phone1.sendSMS(); }, "AA").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(() -> { phone2.sendEmail(); }, "BB").start();
    }
}

class Phone {
    public synchronized void sendSMS() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("------sendSMS");
    }
    public synchronized void sendEmail() {
        System.out.println("------sendEmail");
    }
}/*sendEmail*/
  • 问题五:两个静态同步方法,1部手机,先打印短信还是邮件?
public class Lock_8_5 {
    public static void main(String[] args) throws Exception {
        Phone phone = new Phone();
        new Thread(() -> { phone.sendSMS(); }, "AA").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(() -> { phone.sendEmail(); }, "BB").start();
    }
}

class Phone {
    public static synchronized void sendSMS() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("------sendSMS");
    }
    public static synchronized void sendEmail() {
        System.out.println("------sendEmail");
    }
}/*sendSMS*/
  • 问题六:两个静态同步方法,2部手机,先打印短信还是邮件?
public class Lock_8_6 {
    public static void main(String[] args) throws Exception {
        Phone phone = new Phone();
        Phone phone2 = new Phone();
        new Thread(() -> { phone.sendSMS(); }, "AA").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(() -> { phone2.sendEmail(); }, "BB").start();
    }
}

class Phone {
    public static synchronized void sendSMS() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("------sendSMS");
    }
    public static synchronized void sendEmail() {
        System.out.println("------sendEmail");
    }
}/*sendSMS*/
  • 问题七:1个静态同步方法,1个普通同步方法,1部手机,先打印短信还是邮件?
public class Lock_8_7 {
    public static void main(String[] args) throws Exception {
        Phone phone = new Phone();
        new Thread(() -> { phone.sendSMS(); }, "AA").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(() -> { phone.getHello(); }, "BB").start();
    }
}

class Phone {
    public static synchronized void sendSMS() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("------sendSMS");
    }
    public synchronized void sendEmail() {
        System.out.println("------sendEmail");
    }
}/*sendEmail*/
  • 问题八:1个静态同步方法,1个普通同步方法,2部手机,先打印短信还是邮件
public class Lock_8_8 {
    public static void main(String[] args) throws Exception {
        Phone phone = new Phone();
        Phone phone2 = new Phone();
        new Thread(() -> { phone.sendSMS(); }, "AA").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(() -> { phone2.sendEmail(); }, "BB").start();
    }
}

class Phone {
    public static synchronized void sendSMS() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("------sendSMS");
    }
    public synchronized void sendEmail() {
        System.out.println("------sendEmail");
    }
}/*sendEmail*/

2 多线程锁

  • synchronized实现同步的基础:Java中的每一个对象都可以作为锁。具体表现为以下3种形式。
    • 对于普通同步方法,锁是当前实例对象。
    • 对于静态同步方法,锁是当前类的Class对象。
    • 对于同步方法块,锁是Synchonized括号里配置的对象
  • 当一个线程试图访问同步代码块时,它首先必须得到锁,退出或抛出异常时必须释放锁。
  • 如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁
    • 一个对象里面如果有多个synchronized方法,某一个时刻内,只要一个线程去调用其中的一个synchronized方法了,其它的线程都只能等待,换句话说,某一个时刻内,只能有唯一一个线程去访问这些synchronized方法,锁的是当前对象this,被锁定后,其它的线程都不能进入到当前对象的其它的synchronized方法(问题一、问题二)
  • 不同的实例对象的非静态同步方法因为锁的是各自的实例对象,所以互不影响(问题四)
  • 加个普通方法后发现和同步锁无关(问题三)
  • 所有的静态同步方法用的也是同一把锁——类对象本身,一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,而不管是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同步方法之间,它们只有同一个类的实例对象class!(问题五、问题六)
  • 实例对象锁与类的class对象锁,是两个不同的对象,所以静态同步方法与非静态同步方法之间是不会有竞态条件的。(问题七、问题八)
上一篇:zabbix 邮件报警


下一篇:JUC并发编程(二)