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

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

  • 相关阅读:
    用bash脚本统计代码行数
    Winform应用程序实现通用消息窗口
    文件管理工具“三剑客” #Everything #SpaceSniffer #Clover
    Jenkins pipeline:pipeline 语法详解
    Android studio安装教程
    恶意代码分析实战 shellcode分析 lab 191 192 193 整体来说 对汇编代码的分析要求较高 因为没法直接反编译为C代码看
    恶意代码分析实战 加壳与脱壳 lab 181 182 183 184 185 手动脱壳和自动脱壳操作
    恶意代码分析实战 IDA分析 lab 73 一个通过感染主机exe 修改kernel.dll为恶意dll的后门程序 要做清理的话 是很难的!
    恶意代码分析实战 隐蔽的恶意代码启动 lab121 122 123 124 进程注入、进程替换、hook procmon监控os api调用不行 数据分析还是要sysmon
    恶意代码分析实战 ollydbg使用来了 Lab 91 92 93
  • 原文地址:https://www.cnblogs.com/Jemb/p/11617145.html
Copyright © 2020-2023  润新知