多线程8种锁的介绍

// 首先看一个简单的demo
 class Phone{//手机这个资源类
    public synchronized  void sendEmail()throws Exception{
        System.out.println("***********发送邮件");
    }
    public synchronized  void sendSMS()throws Exception{
        System.out.println("***********发送短信");
    }
}
public class Lock8 {
    public static void main(String[] args) throws Exception {
        Phone phone=new Phone();
        new Thread(()->{
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"A").start();
        Thread.sleep(100);//保证A线层先运行
        new Thread(()->{
            try {
                phone.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"B").start();
    }
}

下面是8种情况

  1. 标准访问,请问先打印邮件还是短信? 一个人操作手机的两个功能
  2. 邮件新增暂停4秒钟的方法,请问先打印邮件还是短信?
class Phone{
   public synchronized  void sendEmail()throws Exception{
   //    try {TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) {  e.printStackTrace(); }
       System.out.println("***********发送邮件");
   }
   public synchronized  void sendSMS()throws Exception{
       System.out.println("***********发送短信");
   }
}
public class Lock8 {
   public static void main(String[] args) throws Exception {
       Phone phone=new Phone();
       new Thread(()->{
           try {
               phone.sendEmail();
           } catch (Exception e) {
               e.printStackTrace();
           }
       },"A").start();
       Thread.sleep(100);
       new Thread(()->{
           try {
               phone.sendSMS();
           } catch (Exception e) {
               e.printStackTrace();
           }
       },"B").start();
   }
}
//以上两种结果运行结果都为:
//***********发送邮件
//***********发送短信
解释:  一个对象里面如果有多个synchronized方法,某一个时刻内,只要一个线程去调用其中的一个synchronized方法了,
其它的线程都只能等待,换句话说,某一个时刻内,只能有唯一一个线程去访问这些synchronized方法
锁的是当前对象this,被锁定后,其它的线程都不能进入到当前对象的其它的synchronized方法
  1. 新增普通的hello方法,请问先打印邮件还是hello
  2. 有两部手机,请问先打印邮件还是短信?
class Phone{
   public synchronized  void sendEmail()throws Exception{
     try {TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) {  e.printStackTrace(); }
       System.out.println("***********发送邮件");
   }
   public synchronized  void sendSMS()throws Exception{
       System.out.println("***********发送短信");
   }
    public void hello(){
       System.out.println("***********hello");
   }
}
}
public class Lock8 {
   public static void main(String[] args) throws Exception {
       Phone phone=new Phone();
         Phone phone2=new Phone();
       new Thread(()->{
           try {
               phone.sendEmail();
           } catch (Exception e) {
               e.printStackTrace();
           }
       },"A").start();
       Thread.sleep(100);
       new Thread(()->{
           try {
            //phone.hello();//锁3
            phone2.sendSMS()//锁4
           } catch (Exception e) {
               e.printStackTrace();
           }
       },"B").start();
   }
}
//3结果运行结果为:
***********hello
***********发送邮件
解释:加个普通方法后发现和同步锁无关
//4结果运行结果为:
***********发送短信
***********发送邮件
解释:换成两个对象后,不是同一把锁了,情况立刻变化
  1. 两个静态同步方法,同一部手机,请问先打印邮件还是短信?
  2. 两个静态同步方法,2部手机,请问先打印邮件还是短信?
class Phone{
  public static synchronized  void sendEmail()throws Exception{
    try {TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) {  e.printStackTrace(); }
      System.out.println("***********发送邮件");
  }
  public static synchronized  void sendSMS()throws Exception{
      System.out.println("***********发送短信");
  }
   public void hello(){
      System.out.println("***********hello");
  }
}
}
public class Lock8 {
  public static void main(String[] args) throws Exception {
      Phone phone=new Phone();
        Phone phone2=new Phone();
      new Thread(()->{
          try {
              phone.sendEmail();
          } catch (Exception e) {
              e.printStackTrace();
          }
      },"A").start();
      Thread.sleep(100);
      new Thread(()->{
          try {
           //phone.sendSMS();//锁5
           phone2.sendSMS()//锁6
          } catch (Exception e) {
              e.printStackTrace();
          }
      },"B").start();
  }
}
//5,6l两种运行结果为:
//***********发送邮件
//***********发送短信
解释:对于静态同步方法,锁是当前类的Class对象
  1. 1个静态同步方法,1个普通同步方法,1部手机,请问先打印邮件还是短信?
  2. 1个静态同步方法,1个普通同步方法,2部手机,请问先打印邮件还是短信?
class Phone{
  public static synchronized  void sendEmail()throws Exception{
    try {TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) {  e.printStackTrace(); }
      System.out.println("***********发送邮件");
  }
  public synchronized  void sendSMS()throws Exception{
      System.out.println("***********发送短信");
  }
   public void hello(){
      System.out.println("***********hello");
  }
}
}
public class Lock8 {
  public static void main(String[] args) throws Exception {
      Phone phone=new Phone();
        Phone phone2=new Phone();
      new Thread(()->{
          try {
              phone.sendEmail();
          } catch (Exception e) {
              e.printStackTrace();
          }
      },"A").start();
      Thread.sleep(100);
      new Thread(()->{
          try {
           //phone.sendSMS();//锁7
          phone2.sendSMS()//锁8
          } catch (Exception e) {
              e.printStackTrace();
          }
      },"B").start();
  }
}
//7,8l两种运行结果为:
//***********发送短信
//***********发送邮件
解释:线程一static锁的是class锁, 普通的同步方法锁的是This实例对象,根本不相干,静态锁住的是class,普通方法用的是对象实例的锁
  • synchronized实现同步的基础:Java中的每一个对象都可以作为锁。
  • 具体表现为以下3种形式。
  • 对于普通同步方法,锁是当前实例对象。
  • 对于静态同步方法,锁是当前类的Class对象。
  • 对于同步方法块,锁是Synchonized括号里配置的对象。
    也就是说如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁,
    可是别的实例对象的非静态同步方法因为跟该实例对象的非静态同步方法用的是不同的锁,
    所以毋须等待该实例对象已获取锁的非静态同步方法释放锁就可以获取他们自己的锁。
    所有的静态同步方法用的也是同一把锁——类对象本身,
    这两把锁(this/Class)是两个不同的对象,所以静态同步方法与非静态同步方法之间是不会有竞态条件的。
    但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,
    而不管是同一个实例对象的静态同步方法之间,
    还是不同的实例对象的静态同步方法之间,只要它们同一个类的实例对象!