zoukankan      html  css  js  c++  java
  • Synchronized理解

     我们可以利用synchronized关键字来对程序进行加锁。它既可以用来声明一个synchronized代码块,也可以直接标记静态方法或者实例方法。
     
     
    synchronized怎么实现线程的同步?
    早期的synchronized属于重量级锁,依赖于mutex lock实现,线程之间的切换涉及到 用户态--》内核态的转换,由于状态的改变设计一个线程的所有变量状态的保存,以及空间的重新分配,系统开销十分巨大。
    jdk1.6之后,引入了偏向锁,轻量级锁,在并发程度不是很高的情况下,也能保证良好的性能。
     
     
    锁升级的步骤?
    无锁--》偏向锁--》轻量级锁--》重量级锁
    偏向锁: 目的是减少同一线程获取锁的代价。大多数情况下,锁是不存在多线程竞争的,总是由同一个线程多次获得。
           偏向锁如何加:如果一个线程获得了锁,锁就进入了偏向模式。对象头MarkWorld的锁标志微为01,同时记录了该线程的线程id,当该线程再次请求锁的时候,无需再做任何同步操作,只需检查MarkWorld的锁标记位位现象锁以及线程id相同即可,色和功能区了中间有关锁申请的操作
    轻量级锁:有偏向锁升级而来,偏向锁运行的一个线程进入同步块的情况下。当第二个线程加入锁竞争的时候,偏向锁就会升级为轻量级的锁。
      适用场景:线程交替执行同步块。
     
     

    Synchronized和ReentrantLock区别?
    1.Synchronized基于操作 MarkWord,ReentrantLock 调用Unsafe类的方法
    2.ReentrantLock可以对获取锁的等待时间进行设置,避免死锁
    3.ReentrantLock可以实现公平,非公平锁
    4.ReentrantLock配合condition可以实现更加精确的线程控制
    5.Synchronized无需进行锁的释放,ReentrantLock需要进行锁的释放

     
     
     
     

    synchronized的线程同步在JVM层面,通过字节码中的monitorenter和monitorexit指令。

        public void test(Object lock){
            synchronized (lock){
                lock.toString();
            }
        }

    如果使用synchronized标记方法,你会看到字节码中方法的访问标记包括ACC_SYNCHRONIZED。
    该标记表示在进入该方法时,Java 虚拟机同样需要进行monitorenter操作。

    /**
     * @Author:daboluo
     * @Date: 2019/9/29 8:58
     * @Version 1.0
     *
     * SynchronizedCountExample保证多线程相加原子性
     */
    public class SynchronizedCountExample {
    
        private static int clientTotal = 5000;
    
        private static int threadTotal = 200;
    
        private static int count = 0;
    
    
        public static void main(String[] args) throws Exception{
            ExecutorService exec = Executors.newCachedThreadPool();
            final Semaphore semaphore = new Semaphore(threadTotal);
            final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
            for (int i = 0; i < clientTotal; i++) {
                exec.execute(()->{
                    try {
                        semaphore.acquire();
                        add();
                        semaphore.release();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    countDownLatch.countDown();
                });
            }
            countDownLatch.await();
            exec.shutdown();
            System.out.println("count = " + count);
        }
    
    
        /**
         *
         * synchronized : 不可终端的,适合竞争不激烈的,可读性号
         * lovk:可中断锁,多样化同步,竞争激烈时能维持常态
         * atomic:竞争激烈时能维持常态,比lock的性能号;侄儿能同步一个值
         *
         *
         */
        private synchronized static void add(){
            count++;
        }
    
    }
    
    /**
     * 结果:
     * count = 5000
     * 
     */
    

      

    锁优化的方案?

    1.降低锁的时间(只需要在有线程安全要求的程序代码上加锁,而不是整个代码块加)

    2.降低锁的细粒度(之前的ConcurrentHashMap通过减少锁的细粒度,提升性能)

    3.读写分离(应用系统中,读操作次数远远大于写操作)

    4.锁的粗化(通过把synchronized加载for循环外,避免每次for循环都涉及线程的切换)

    5.锁消除(StringBuffer是一个局部变量,堆栈封闭,方法没有把StringBuffer返回,所以不可能会有多线程去访问它。

    当我们在一些不会有线程安全的情况下使用这些类的方法时,达到某些条件时,编译器会将锁消除来提高性能。) 

  • 相关阅读:
    关闭编辑easyui datagrid table
    sql 保留两位小数+四舍五入
    easyui DataGrid 工具类之 util js
    easyui DataGrid 工具类之 后台生成列
    easyui DataGrid 工具类之 WorkbookUtil class
    easyui DataGrid 工具类之 TableUtil class
    easyui DataGrid 工具类之 Utils class
    easyui DataGrid 工具类之 列属性class
    oracle 卸载
    “云时代架构”经典文章阅读感想七
  • 原文地址:https://www.cnblogs.com/Jemb/p/11617145.html
Copyright © 2011-2022 走看看