JUC并发编程(二)

8锁现象

在并发编程中,一直在谈论锁,但是锁到底是什么呢?它锁的是什么?

首先看下以下8个问题

1、一部手机,两个线程,标准访问,请问先打印邮件还是短信?
2、邮件方法暂停4秒钟,请问先打印邮件还是短信?
3、新增一个普通方法hello()没有同步,请问先打印邮件还是hello?
4、两部手机、请问先打印邮件还是短信?
5、两个静态同步方法,同一部手机,请问先打印邮件还是短信?
6、两个静态同步方法,2部手机,请问先打印邮件还是短信?
7、一个普通同步方法,一个静态同步方法,同一部手机,请问先打印邮件还是短信?
8、一个普通同步方法,一个静态同步方法,2部手机,请问先打印邮件还是短信?

看下程序运行的效果:

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

public class Test1 {
    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.sendSMS();
        },"B").start();
    }
}

/**
 * 手机,发短信,发邮件
 */
class Phone{

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

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

结果:
JUC并发编程(二)
2、邮件方法暂停4秒钟,请问先打印邮件还是短信?

public class Test2 {
    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.sendSMS();
        },"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 sendSMS(){
        System.out.println("sendSMS");
    }
}

结果:
JUC并发编程(二)
3、新增一个普通方法hello()没有同步,请问先打印邮件还是hello?

public class Test3 {
      public static void main(String[] args) {

        Phone3 phone = new Phone3();

        new Thread(() -> { // 一开始就执行了
            phone.sendEmail();
        }, "A").start();

        // 干扰
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> { // 一秒后执行
            phone.hello();
        }, "B").start();

    }
}


/**
 *手机,发短信,发邮件
 */
class Phone3 {
 
    public synchronized void sendEmail() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sendEmail");
    }

    public synchronized void sendMS() {
        System.out.println("sendMS");
    }

    public void hello() {
        System.out.println("hello");
    }

}

结果:
JUC并发编程(二)
4、两部手机、请问先打印邮件还是短信?

public class Test4 {

    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.sendMS();
        }, "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 sendMS() {
        System.out.println("sendMS");
    }

}

结果:
JUC并发编程(二)
5、两个静态同步方法,同一部手机,请问先打印邮件还是短信?

 public class Test5 {
     public static void main(String[] args) {
              Phone5 phone = new Phone5();

         new Thread(() -> { // 一开始就执行了
           phone.sendEmail();
       }, "A").start();

       // 干扰
       try {
           TimeUnit.SECONDS.sleep(1);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       new Thread(() -> { // 一秒后执行
           phone.sendMS();
       }, "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 sendMS() {
       System.out.println("sendMS");
   }

}

结果:
JUC并发编程(二)
6、两个静态同步方法,2部手机,请问先打印邮件还是短信?

public class Test6 {
public static void main(String[] args) {
        Phone5 phone = new Phone5();
        Phone5 phone2 = new Phone5();

        new Thread(() -> { // 一开始就执行了
        phone.sendEmail();
        }, "A").start();

        // 干扰
        try {
        TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
        e.printStackTrace();
        }

        new Thread(() -> { // 一秒后执行
        phone2.sendMS();
        }, "B").start();

        }

        }

// 手机,发短信,发邮件
class Phone6 {
       public static synchronized void sendEmail() {
        // 善意的延迟
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sendEmail");
    }

    public static synchronized void sendMS() {
        System.out.println("sendMS");
    }

}

结果:
JUC并发编程(二)
7、一个普通同步方法,一个静态同步方法,同一部手机,请问先打印邮件还是短信?

public class Test7 {
    
    public static void main(String[] args) {
           Phone7 phone = new Phone7();

        new Thread(() -> { // 一开始就执行了
            phone.sendEmail();
        }, "A").start();

        // 干扰
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> { // 一秒后执行
            phone.sendMS();
        }, "B").start();

    }
}


class Phone7{
    // CLASS
    public static synchronized void sendEmail() {
        // 善意的延迟
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sendEmail");
    }

    // 对象
    // 普通同步方法
    public synchronized void sendMS() {
        System.out.println("sendMS");
    }

}

结果:
JUC并发编程(二)

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

public class Test8 {

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

        new Thread(() -> { // 一开始就执行了
            phone.sendEmail();
        }, "A").start();

        // 干扰
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> { // 一秒后执行
            phone2.sendMS();
        }, "B").start();

    }

}



class Phone8{

    // CLASS
    public static synchronized void sendEmail() {
        // 善意的延迟
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sendEmail");
    }

    // 对象
    // 普通同步方法
    public synchronized void sendMS() {
        System.out.println("sendMS");
    }

}

结果:
JUC并发编程(二)

总结

  1. 锁是一种竞争机制,一个方法加锁,一个方法没有加锁,那么普通方法就会先运行,因为它不要去竞争!
  2. 被synchornized修饰的同步方法,锁的对象是方法的调用者。谁先调用,谁先执行!
  3. 被synchronized修饰和static修饰的方法,锁的对象是类的class对象,唯一的!
上一篇:Java多线程之八锁问题


下一篇:linux下使用smtp+shell脚本实现服务器存活状态监控