zoukankan      html  css  js  c++  java
  • 多线程(二)Synchronized

      synchronized是Java中的关键字,是一种同步锁,按类型可以分为同步方法和同步代码块。

     非同步实例方法&同步实例方法:

    非同步实例方法:

    public class TestSync {
        public static void main(String[] args) throws InterruptedException {
            Cls c = new Cls();
            new Thread() {
                @Override
                public void run() {
                    try {
                        c.method();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
            }.start();
            
            new Thread() {
                @Override
                public void run() {
                    try {
                        c.method();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
            }.start();
        }
    }
    
    class Cls {
    
        public void method() throws InterruptedException {
            Thread.sleep(10);
            System.out.println(Thread.currentThread().getName() + " menthod begin..");
            Thread.sleep(10);
            System.out.println(Thread.currentThread().getName() + " menthod end..");
        }
    
    
    }
    View Code

    执行结果(场景:同步方法属于同一个实例对象):

    Thread-0 menthod begin..
    Thread-1 menthod begin..
    Thread-1 menthod end..
    Thread-0 menthod end..

    同步实例方法:

    public class TestSync {
        public static void main(String[] args) throws InterruptedException {
            Cls c = new Cls();
            new Thread() {
                @Override
                public void run() {
                    try {
                        c.method();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
            }.start();
            
            new Thread() {
                @Override
                public void run() {
                    try {
                        c.method();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
            }.start();
        }
    }
    
    class Cls {
    
        public synchronized void method() throws InterruptedException {
            Thread.sleep(10);
            System.out.println(Thread.currentThread().getName() + " menthod1 begin..");
            Thread.sleep(10);
            System.out.println(Thread.currentThread().getName() + " menthod1 end..");
        }
    
    }
    View Code

    执行结果:

    Thread-0 menthod1 begin..
    Thread-0 menthod1 end..
    Thread-1 menthod1 begin..
    Thread-1 menthod1 end..

    同步实例方法&同步静态方法:

    同步实例方法(场景:同步方法属于不同的实例对象):

    public class TestSync {
        public static void main(String[] args) throws InterruptedException {
            Cls c = new Cls();
            new Thread() {
                @Override
                public void run() {
                    try {
                        c.method();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
            }.start();
            Cls c1 = new Cls();
            new Thread() {
                @Override
                public void run() {
                    try {
                        c1.method();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
            }.start();
        }
    }
    
    class Cls {
    
    
        public static synchronized void staticMethod() throws InterruptedException {
            Thread.sleep(10);
            System.out.println(Thread.currentThread().getName() + " staticMenthod begin..");
            Thread.sleep(10);
            System.out.println(Thread.currentThread().getName() + " staticMenthod end..");
        }
        
        
        public synchronized void method() throws InterruptedException {
            Thread.sleep(10);
            System.out.println(Thread.currentThread().getName() + " menthod begin..");
            Thread.sleep(10);
            System.out.println(Thread.currentThread().getName() + " menthod end..");
        }
    
    }
    View Code
    Thread-1 menthod begin..
    Thread-0 menthod begin..
    Thread-0 menthod end..
    Thread-1 menthod end..

    同步静态方法:

    public class TestSync {
        public static void main(String[] args) throws InterruptedException {
            new Thread() {
                @Override
                public void run() {
                    try {
                        Cls.staticMethod();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
            }.start();
            new Thread() {
                @Override
                public void run() {
                    try {
                        Cls.staticMethod();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
            }.start();
        }
    }
    
    class Cls {
    
    
        public static synchronized void staticMethod() throws InterruptedException {
            Thread.sleep(10);
            System.out.println(Thread.currentThread().getName() + " staticMenthod begin..");
            Thread.sleep(10);
            System.out.println(Thread.currentThread().getName() + " staticMenthod end..");
        }
        
        
        public synchronized void method() throws InterruptedException {
            Thread.sleep(10);
            System.out.println(Thread.currentThread().getName() + " menthod begin..");
            Thread.sleep(10);
            System.out.println(Thread.currentThread().getName() + " menthod end..");
        }
    
    }
    View Code

    执行结果:

    Thread-0 staticMenthod begin..
    Thread-0 staticMenthod end..
    Thread-1 staticMenthod begin..
    Thread-1 staticMenthod end..

    结论:

    • 被锁对象是类的实例对象时,synchronized只在同一实例中作用
    • 被锁对象是类对象时,即使new多个实例对象,但他们仍然是属于同一个类,依然会被锁住,即线程之间保证同步关系。

    锁机制 

    public class TestSync {
        
        public  void lockClass() {
            synchronized(TestSync.class) {
                System.out.println("lockClass ..");
            }
        }
        
        public synchronized void lockObject() {
            System.out.println("lockObject ..");
        }
    }

      使用【javap -v TestSync.class】来反编译以上代码,结果如下:

      public void lockClass();
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=2, locals=2, args_size=1
             0: ldc           #1                  // class com/ryj/thread/TestSync
             2: dup
             3: astore_1
             4: monitorenter
             5: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
             8: ldc           #21                 // String lockClass ..
            10: invokevirtual #23                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
            13: aload_1
            14: monitorexit
            15: goto          21
            18: aload_1
            19: monitorexit
            20: athrow
            21: return
    
      public synchronized void lockObject();
        descriptor: ()V
        flags: ACC_PUBLIC, ACC_SYNCHRONIZED
        Code:
          stack=2, locals=1, args_size=1
             0: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
             3: ldc           #35                 // String lockObject ..
             5: invokevirtual #23                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
             8: return

      对于同步方法,JVM采用ACC_SYNCHRONIZED标记符来实现同步。 对于同步代码块。JVM采用monitorentermonitorexit两个指令来实现同步。

      方法级的同步是隐式的。同步方法的常量池中会有一个ACC_SYNCHRONIZED标志。当某个线程要访问某个方法的时候,会检查是否有ACC_SYNCHRONIZED,如果有设置,则需要先获得监视器锁,然后开始执行方法,方法执行之后再释放监视器锁。这时如果其他线程来请求执行方法,会因为无法获得监视器锁而被阻断住。值得注意的是,如果在方法执行过程中,发生了异常,并且方法内部并没有处理该异常,那么在异常被抛到方法外面之前监视器锁会被自动释放。

      执行monitorenter指令理解为加锁,执行monitorexit理解为释放锁。 每个对象维护着一个记录着被锁次数的计数器。未被锁定的对象的该计数器为0,当一个线程获得锁(执行monitorenter)后,该计数器自增变为 1 ,当同一个线程再次获得该对象的锁的时候,计数器再次自增。当同一个线程释放锁(执行monitorexit指令)的时候,计数器再自减。当计数器为0的时候。锁将被释放,其他线程便可以获得锁。

      Java的线程是映射到操作系统原生线程之上的,如果要阻塞或唤醒一个线程就需要操作系统的帮忙,这就要从用户态转换到核心态,因此状态转换需要花费很多的处理器时间,对于代码简单的同步块(如被synchronized修饰的get 或set方法)状态转换消耗的时间有可能比用户代码执行的时间还要长,所以说synchronized是java语言中一个重量级的操纵。

  • 相关阅读:
    保险精算导论
    天津大学C语言程序设计
    会计学
    WIN10 CH340安装失败
    好用的浏览器插件
    好用的壁纸软件
    30讲 窗口看门狗
    STM32替换Arduino直通车
    stm32系列芯片独立看门狗(IWDG)溢出时间计算原理
    AD 电子元器件图片、名称及符号对照
  • 原文地址:https://www.cnblogs.com/ryjJava/p/14398775.html
Copyright © 2011-2022 走看看