zoukankan      html  css  js  c++  java
  • 线程安全

    线程安全测试:

    @Slf4j
    public class ConcurrencyTest {
        
        public static int clientTotal = 5000;//请求总数
        
        public static int threadTotal = 200;//允许并发线程数
        
        public static int count = 0;//
        
        public static void main(String[] args) throws Exception{
            //定义线程池
            ExecutorService executorService = Executors.newCachedThreadPool();
            //定义信号量
            final Semaphore semaphore = new Semaphore(threadTotal);
            //计数器
            final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
            
            for(int i = 0; i < clientTotal; i++){
                executorService.execute(()->{
                    try {
                        semaphore.acquire();//判断进程是否允许被执行
                        add();
                        semaphore.release();
                    }catch (Exception e){
                        log.error("Exception--- " + e.getMessage());
                    }
                    countDownLatch.countDown();
                    
                });
            }
            countDownLatch.await();
            executorService.shutdown();
            log.info("count:{}" + count);
        }
        
        private static void add(){
            count++;
        }
    }

     线程安全性:

            原子性:同一时刻只能有一个线程来操作。

            可见性:一个线程对主内存的修改可以及时的被其他线程观察到。

            有序性:

    原子性 Atomic包:

    public static AtomicInteger count = new AtomicInteger(0);//
    
    private static void add(){
            count.incrementAndGet();
    }

     incrementAndGet 实现:

    public final int incrementAndGet() {
            return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
        }
    unsafe.getAndAddInt(this, valueOffset, 1) 实现:
    public final int getAndAddInt(Object var1, long var2, int var4) {
            int var5;
            do {
                var5 = this.getIntVolatile(var1, var2);
            } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
    
            return var5;
    }
    public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5); Java底层方法
    当前值和底层的值相同,则更新值。
    CAS:compareAndSwap

    AtomicLong是作用是对长整形进行原子操作,显而易见,在java1.8中新加入了一个新的原子类LongAdder,该类也可以保证Long类型操作的原子性,相对于AtomicLong,
    LongAdder有着更高的性能和更好的表现,可以完全替代AtomicLong的来进行原子操作。

    在32位操作系统中,64位的long 和 double 变量由于会被JVM当作两个分离的32位来进行操作,所以不具有原子性。而使用AtomicLong能让long的操作保持原子型。

     AtomicStampReference : CAS的ABA问题

    原子性对比:

    synchronized:不可中断锁,适合竞争不激烈,可读性好;

    Lock:可中断锁,多样化同步,竞争激烈时能维持常态;

    Atomic:竞争激烈时能维持常态,比Lock性能好,只能同步一个值。

    可见性:

    • 线程交叉执行
    • 重排序结合线程交叉执行;
    • 共享变量更新后的值没有在工作内存与主存间及时更新。

    可见性 - synchronized

    •  线程解锁前,必须把共享变量的最新值刷新到主内存;
    • 线程加锁时,将清空工作内存中共享变量的值,使用共享变量时需要从主内存中重新读取最新的值。

    可见性 - volatile

              通过加入内存屏障和禁止重排序优化来实现

    • 对volatile变量写操作时,会在操作后加入一条store屏障指令,将本地内存的共享变量值刷新到主内存;
    • 对volatile变量读操作时,会在操作前加入一条load屏障指令,从主内存总读取共享变量。

    volatile不具有原子性,适合做为状态标记量。

    发布对象

         使一个对象能够被当前范围之外的代码所使用

    对象溢出

          一种错误的发布,当一个对象还没有构造完成时,就使他被其他线程所见。

    线程不安全,当两个线程同时拿到Null的时候,就会出现问题。

    加锁的情况下也有可能出现线程不安全:

     因为JVM和cpu的优化,发生了指令重排

    1.memory = allocate() 分配对象的内存空间;

    2.instance = memory 设置instance指向刚分配的内存;

    3.ctorInstance() 初始化对象

     

     使用volatile关键字来禁止指令重排

    使用枚举

    安全发布对象的方法

    • 在静态初始化函数中初始化一个对象引用;
    • 将对象的引用保存到volatile类型域或者AtomicReference对象中;
    • 将对象的引用保存到某个正确构造对象的final类型域中;
    • 将对象的引用保存到一个由锁保护的域中。

    final关键字:

    • 修饰类:不能被继承;
    • 修饰方法:1.锁定方法不能被继承类修改;2.效率()
    • 修饰变量:基本数据类型变量,引用数据类型变量

    final如果修饰引用类型的变量时,只是不允许指向另一个对象,但是变量的值可以修改。

    不可变对象

     

    线程封闭

    • Ad-hoc线程封闭:程序控制实现,最糟糕
    • 堆栈封闭:局部变量,无并发问题;
    • ThreadLocal 线程封闭:非常好的方法。

    String类:String对象是不可改变的(引用类型)。字符串一旦创建,内容不能再改变。

    当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。

     Java8的DateTimeFormatter是线程安全的,而SimpleDateFormat并不是线程安全。

    同步容器

    • ArrayList:Vector 、Stack
    • HashMap:HashTable
    • Collections.synchronizedXXX(List,Set,Map)
  • 相关阅读:
    Build 2016: 发布明天的云创新来服务今天的开发者
    微软在Build 2016开发者大会中发布 “认知服务”,牛津计划有正式名字啦!
    流行开源软件云上体验周 ——一种正确的云上开源软件体验姿势!
    让每个人都体验到来自云端的智能
    hdmap相关单词
    绝对误差和相对误差的定义
    高速公路之匝道
    hdmap相关
    虚拟参考站(VRS)
    matlab之结构体数组struct
  • 原文地址:https://www.cnblogs.com/taiguyiba/p/11308722.html
Copyright © 2011-2022 走看看