JUC(二)——深入理解锁机制

懵懂的女人 提交于 2019-12-19 12:59:23

对于锁大家肯定都不陌生,锁分为synchronize和lock

但是大家是否知道锁到底锁住的是什么呢?

接下来我们举几个例子来了解锁(这里使用synchronize来演示)

  • 1、该代码先打印的是短信还是邮件?
       class Phone
       {
       
           public synchronized void sendSMS() throws Exception
           {
               System.out.println("------短信");
           }
           public synchronized void sendEmail() throws Exception
           {
               System.out.println("------邮件");
           }
       
           public void getHello()
           {
               System.out.println("------hello");
           }
       
       }
       public class Lock
       {
           public static void main(String[] args) throws Exception
           {
       
               Phone phone = new Phone();
       
               new Thread(() -> {
                   try {
                       phone.sendSMS();
                   } catch (Exception e) {
                       e.printStackTrace();
                   }
               }, "AA").start();
       
               Thread.sleep(100);
       
               new Thread(() -> {
                   try {
                       phone.sendEmail();
                   } catch (Exception e) {
                       e.printStackTrace();
                   }
               }, "BB").start();
           }
       }
    
    • 结果:短信(我们结合第二个例子一起解释)
  • 2、停4秒在短信方法内,该代码先打印的是短信还是邮件?
    •   class Phone
        {
        
            public synchronized void sendSMS() throws Exception
            {
                TimeUnit.SECONDS.sleep(4);
                System.out.println("------短信");
            }
            public synchronized void sendEmail() throws Exception
            {
                System.out.println("------邮件");
            }
        
            public void getHello()
            {
                System.out.println("------hello");
            }
        
        }
        public class Lock
        {
            public static void main(String[] args) throws Exception
            {
        
                Phone phone = new Phone();
        
                new Thread(() -> {
                    try {
                        phone.sendSMS();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }, "AA").start();
        
                Thread.sleep(100);
        
                new Thread(() -> {
                    try {
                        phone.sendEmail();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }, "BB").start();
            }
        }
      
    • 结果:短信
    • 讲解:
      • 一个对象里面如果有多个被synchronize锁住的普通方法,如果某一个时刻内,只要有一个线程去调用其中的一个synchronized方法了,那么其它的线程都只能等待
      • 换句话说,某一个时刻内,只能有唯一一个线程去访问这些synchronized方法
      • 此时锁的是当前对象this,被锁定后,其它的线程都不能进入到当前对象的其它的synchronized方法
  • 3、普通的hello方法,该代码先打印短信还是hello
    •   class Phone
        {
        
            public synchronized void sendSMS() throws Exception
            {
                TimeUnit.SECONDS.sleep(4);
                System.out.println("------短信");
            }
            public synchronized void sendEmail() throws Exception
            {
                System.out.println("------邮件");
            }
        
            public void getHello()
            {
                System.out.println("------hello");
            }
        
        }
        public class Lock
        {
            public static void main(String[] args) throws Exception
            {
        
                Phone phone = new Phone();
        
                new Thread(() -> {
                    try {
                        phone.sendSMS();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }, "AA").start();
        
                Thread.sleep(100);
        
                new Thread(() -> {
                    try {
                        phone.getHello();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }, "BB").start();
            }
        }
      
    • 结果:hello
    • 结论: 普通方法和同步锁无关
  • 4、现在有两部手机,该代码先打印的是短信还是邮件?
    •   class Phone
        {
        
            public synchronized void sendSMS() throws Exception
            {
                TimeUnit.SECONDS.sleep(4);
                System.out.println("------短信");
            }
            public synchronized void sendEmail() throws Exception
            {
                System.out.println("------邮件");
            }
        
            public void getHello()
            {
                System.out.println("------hello");
            }
        
        }
        public class Lock
        {
            public static void main(String[] args) throws Exception
            {
        
                Phone phone = new Phone();
        		  Phone phone2 = new Phone();
                new Thread(() -> {
                    try {
                        phone.sendSMS();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }, "AA").start();
        
                Thread.sleep(100);
        
                new Thread(() -> {
                    try {
                        phone2.getHello();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }, "BB").start();
            }
        }
      
    • 结果:邮件
    • 结论: 锁的是对象,两个不同的对象是互不影响的
  • 5、两个静态同步方法,1部手机,该代码先打印的是短信还是邮件?
    •   class Phone
        {
        
            public static synchronized void sendSMS() throws Exception
            {
                TimeUnit.SECONDS.sleep(4);
                System.out.println("------短信");
            }
            public static synchronized void sendEmail() throws Exception
            {
                System.out.println("------邮件");
            }
        
            public void getHello()
            {
                System.out.println("------hello");
            }
        
        }
        public class Lock
        {
            public static void main(String[] args) throws Exception
            {
        
                Phone phone = new Phone();
        
                new Thread(() -> {
                    try {
                        phone.sendSMS();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }, "AA").start();
        
                Thread.sleep(100);
        
                new Thread(() -> {
                    try {
                        phone.sendEmail();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }, "BB").start();
            }
        }
      
    • 结果:短信(和下一个例子一起说)
  • 6、两个静态同步方法,2部手机,该代码先打印的是短信还是邮件?
    •  class Phone
       {
       
           public static synchronized void sendSMS() throws Exception
           {
               TimeUnit.SECONDS.sleep(4);
               System.out.println("------短信");
           }
           public static synchronized void sendEmail() throws Exception
           {
               System.out.println("------邮件");
           }
       
           public void getHello()
           {
               System.out.println("------hello");
           }
       
       }
       public class Lock
       {
           public static void main(String[] args) throws Exception
           {
       
               Phone phone = new Phone();
       		 Phone phone2 = new Phone();
               new Thread(() -> {
                   try {
                       phone.sendSMS();
                   } catch (Exception e) {
                       e.printStackTrace();
                   }
               }, "AA").start();
       
               Thread.sleep(100);
       
               new Thread(() -> {
                   try {
                       phone2.sendEmail();
                   } catch (Exception e) {
                       e.printStackTrace();
                   }
               }, "BB").start();
           }
       }
      
    • 结果:短信
    • 结论: 对静态方法加锁,锁住的不在是对象,而是这个类。即该类中所有的静态加锁方法用的是同一把锁
  • 7、1个静态同步方法,1个普通同步方法,1部手机,该代码先打印的是短信还是邮件?
    •   class Phone
        {
        
            public static synchronized void sendSMS() throws Exception
            {
                TimeUnit.SECONDS.sleep(4);
                System.out.println("------短信");
            }
            public synchronized void sendEmail() throws Exception
            {
                System.out.println("------邮件");
            }
        
            public void getHello()
            {
                System.out.println("------hello");
            }
        
        }
        public class Lock
        {
            public static void main(String[] args) throws Exception
            {
        
                Phone phone = new Phone();
                
                new Thread(() -> {
                    try {
                        phone.sendSMS();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }, "AA").start();
        
                Thread.sleep(100);
        
                new Thread(() -> {
                    try {
                        phone.sendEmail();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }, "BB").start();
            }
        }
      
    • 结果:邮件(结论和下个例子一起说)
  • 8、1个静态同步方法,1个普通同步方法,2部手机,先打印短信还是邮件
    •   class Phone
        {
        
            public static synchronized void sendSMS() throws Exception
            {
                TimeUnit.SECONDS.sleep(4);
                System.out.println("------短信");
            }
            public synchronized void sendEmail() throws Exception
            {
                System.out.println("------邮件");
            }
        
            public void getHello()
            {
                System.out.println("------hello");
            }
        
        }
        public class Lock
        {
            public static void main(String[] args) throws Exception
            {
        
                Phone phone = new Phone();
                Phone phone2 = new Phone();
                new Thread(() -> {
                    try {
                        phone.sendSMS();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }, "AA").start();
        
                Thread.sleep(100);
        
                new Thread(() -> {
                    try {
                        phone2.sendEmail();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }, "BB").start();
            }
        }
      
    • 结果:邮件
    • 结论: 静态加锁锁的是类,普通加锁方法锁的是对象,两个锁互不干扰

总结

  • 对于普通同步方法,锁是当前实例对象。
  • 对于静态同步方法,锁是当前类的Class对象。
  • 不同的锁之间或不干扰,上锁的方法和没上锁的方法或不干扰
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!