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返回,所以不可能会有多线程去访问它。

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

  • 相关阅读:
    TEN
    out.println()、document.write()、document.getelementbyid()
    正则表达式
    DOM与BOM
    伪类和伪元素
    Grid(未完全完成)
    position
    表单
    API,WEB API
    Event Flow
  • 原文地址:https://www.cnblogs.com/Jemb/p/11617145.html
Copyright © 2011-2022 走看看