zoukankan      html  css  js  c++  java
  • java面试-synchronized底层实现机制

    一、synchronized的三种应用方式

    1、修饰实例方法,锁是当前实例对象,进入同步代码前要获得当前实例的锁

    /**
     * synchronized修饰实例方法,当前线程的锁是实例对象accountingSync
     * 当一个线程正在访问一个对象的synchronized实例方法,那么其他线程不能访问该对象的其他synchronized方法
     * 一个对象只有一把锁
     */
    public class AccountingSync implements Runnable {
    
        static AccountingSync accountingSync = new AccountingSync();
        //共享资源
        static int i = 0;
        static int j = 0;
    
        public synchronized void increase() {
            i++;
        }
    
        @Override
        public void run() {
            for(int i =0;i<1000000;i++){
                synchronized (this){
                    increase();
                }
            }
        }
    
    
        public static void main(String[] args) throws InterruptedException {
            Thread thread1 = new Thread(accountingSync);
            Thread thread2 = new Thread(accountingSync);
            thread1.start();
            thread2.start();
            thread1.join();
            thread2.join();
            System.out.println(i);
        }
    }  
    /**
     * thread1访问实例对象obj1的synchronized方法,thread2访问实例对象obj1的synchronized方法
     * 这样是允许的,因为两个实例对象锁并不相同。
     * 此时如果两个线程操作数据非共享,线程安全有保证,如果数据共享,线程安全无法保证
     *
     */
    public class AccountingSyncBad implements Runnable {
    
        static int i = 0;
    
        public synchronized void increase() {
            i++;
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 1000000; i++) {
                increase();
            }
        }
    
    
        public static void main(String[] args) throws InterruptedException{
            //new新实例
            Thread thread1 = new Thread(new AccountingSyncBad());
            //new新实例
            Thread thread2 = new Thread(new AccountingSyncBad());
            thread1.start();
            thread2.start();
            thread1.join();
            thread2.join();
            System.out.println(i);
        }
    }   

    2、修饰静态方法,锁是当前类的 class对象,进入同步代码前要获得当前类对象的锁 

    public class AccountingSyncClass implements Runnable{
    
        static int i = 0;
    
        /**
         * synchronized作用于静态方法,锁是当前class对象
         */
        public static synchronized void increase() {
            i++;
        }
    
        /**
         *  increase4Obj方法是实例方法,其对象锁是当前实例对象,
         *  如果别的线程调用该方法,将不会产生互斥现象,毕竟锁对象不同,
         *  但我们应该意识到这种情况下可能会发现线程安全问题(操作了共享静态变量i)。
         */
        public synchronized void increase4Obj(){
            i++;
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 1000000; i++) {
                increase();
    //            increase4Obj();
            }
        }
    
    
        public static void main(String[] args) throws InterruptedException{
            //new新实例
            Thread thread1 = new Thread(new AccountingSyncClass());
            //new新实例
            Thread thread2 = new Thread(new AccountingSyncClass());
            thread1.start();
            thread2.start();
            thread1.join();
            thread2.join();
            System.out.println(i);
        }
    }  

    3、修饰代码块

    synchronized(this) 锁是当前实例对象,
    synchronized(AccountingSync.class) 锁是class对象

    二、synchronized代码块底层原理

    synchronized代码块是由一对monitorenter和monitorexit指令实现的,Monitor对象是同步的基本实现单元。

    现代java虚拟机对sychronized进行了优化,引入了偏斜锁、轻量级锁、重量级锁

    三、java虚拟机对Synchronized的优化

    JVM优化synchronized运行的机制,当JVM检测到不同的竞争情况时,会自动切换到适合的锁实现

    1、当没有竞争出现时,默认会使用偏斜锁JVM 会利用 CAS操作,在对象头上的Mark Word部分设置线程ID,以表示这个对象偏向于当前线程,所以并不涉及真正的互斥锁。这样做的假设是基于在很多应用场景中,大部分对象生命周期中最多会被一个线程锁定,使用偏斜锁可以降低无竞争开销。

    2、有竞争出现时,当有另外的线程试图锁定某个已经被偏斜锁锁定的对象,jvm就会撤销revoke偏斜锁,并切换到轻量级锁。轻量级锁依赖CAS操作Mark Word来试图获取锁,如果成功,就使用轻量级锁,否则继续升级未重量级锁

    PS:锁降级也是存在的,当JVM进入SafePoint安全点的时候,会检查是否有闲置的Monitor,然后试图进行降级。

  • 相关阅读:
    flock对文件锁定读写操作的问题 简单
    hdu 2899 Strange Fuction(二分)
    hdu 2199 Can you solve this equation? (二分)
    poj 3080 Blue Jeans (KMP)
    poj 2823 Sliding Window (单调队列)
    poj 2001 Shortest Prefixes (trie)
    poj 2503 Babelfish (trie)
    poj 1936 All in All
    hdu 3507 Print Article (DP, Monotone Queue)
    fzu 1894 志愿者选拔 (单调队列)
  • 原文地址:https://www.cnblogs.com/wjh123/p/11408571.html
Copyright © 2011-2022 走看看