ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

解决并发问题的方法(有锁、无锁)

2021-06-08 16:37:06  阅读:214  来源: 互联网

标签:无锁 CAS void private 并发 线程 AtomicInteger 有锁 public


1 并发问题解决的方式

  • 无锁
    • 局部变量
    • 不可变对象
    • ThreadLocal
  • 有锁
    • synchronized
    • ReetrantLock

1.1 无锁的解决方式

1.1.1 局部变量

  • 善用局部变量可以避免出现线程安全问题。
  • 当每一个线程都运行同一行代码时,如果只是操作局部变量,则不可能会造成并发问题。因为每个线程操作的变量是局部的,并不存在交际。
  public void test(){
    int i = 0;
    i++;
    System.out.println(i);
  }

1.1.2 不可变对象

  • 这个对象本身是不可以被改变的。自然就不会害怕多个线程去访问它。
    String s = "Hello"
    // “Hello”就是一个不可改变的对象,他就是一个固定的字符串。

1.1.3 ThreadLocal

  • 当多个线程去访问THreadLocal对象是,都会单独的为访问的线程提供一个该对象的副本。即每个对象只会被一个线程操作,自然无并发问题。

1.1.4 CAS原子类

  • CAS = compare and swap 比较并交换
  • CAS中有三个基本操作数
    • 内存地址V
    • 旧的预期值A
    • 要修改的新数值B
  • CAS思想:只有V里面的值和A相等,才会把V里面的值改成B
  • Java中,采用CAS思想的类,都以Atomic开头,基于乐观锁,保证不会出现并发问题。
    // simple using of AtomicInteger
    private AtomicInteger counter = new AtomicInteger(0);
    public void atomicAdd(){
        counter.incrementAndGet();
    }
    // source code of Atomic 
    public class AtomicInteger extends Number implements java.io.Serializable{
        private static final long serialVsersionUID = ...;
        
        // setup to use Unsafe.compareAndSwapInt for updates
        private static final Unsafe unsafe = Unsafe.getUnsafe(); 
        // unsafe 提供硬件级别的原子操作,由于Java无法直接操控底层代码,为此Java需要使用native方法来拓展这部分功能,unsafe就是其中的一个操作入口。
        // unsafe提供了分配、释放内存,挂起、恢复程序,定位对象字段内存地址,修改对象字段值,CAS操作。
        private static final long valueOffset;

        static {
            try{
                valueOffset = unsafe.objectFieldOffset
                    (AtomicInteger.class.getDeclaredField(value));
            } catch(Exception ex){
                throw new Error(ex)
            }
        }
    }
    // source code of getAndAddInt
    // getAndAddInt method is a cas operate in unsafe class
    public final int getAndAddInt(Object var1, long var2, int var4){
        int var5;
        do{
            // use var5 to get the old value
            var5 = this.getIntVolatile(var1, var2);
            
            // compareAndSwapInt = cas
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }
    // a counter of interface which do not have concurrency problem.
    public static class AccessCounter{
        // count the times of the acccess to this interface
        AtomicInteger accessCount = new AtomicInteger(0);

        public void access(){
            accessCount.incrementAndGet();
            sout("reslut is: " + accountCount.get());
        }
    }

CAS操作实际模拟

  1. 两个线程同时对一个变量K(初始值0)加一。
  2. 线程A,线程B,获得K的旧值0.
  3. 线程A,把K加1以后,再次访问主存中的K,发现现在K的值(0)与自己记录的旧值(0)相等,所以生效,把自己操作的结果写入主存(k=0 --> k=1)
  4. 线程B,把K加1以后,再次访问主存中的K,发现现在的K值(1)与自己记录的旧值(0)不等,所以失效。再次记录主存中K的值,作为一个“新”的旧值。
  5. 线程B,把K加1以后,再次访问主存中的K,发现现在的K值(1)与自己记录的旧值(1)相等,所以生效,把自己的操作的结果写入主存(k=1 --> K=2)

1.2 有锁的解决方式

1.2.1 synchronized & reentrandLock

  • 采用悲观锁的策略。
  • synchronized是通过语言层面来实现,reentrandLock是通过编程层面来实现。
    public class Counter{
        private int i = 0;
        
        private ReentrantLock lock = new ReentrantLock();

        // lock by reentrantLock
        public void lockByReentrantLock(){
            lock.lock();
            try{
                add();
            } finally{
                lock.unlock();
            }
        }

        // lock by synchronized
        public synchronized void lockBySynchronized(){
            add();
        }

        private void add(){
            i++;
        }
    }
  • 加锁的原理:
  • 线程A和线程B同时更新一个资源
  • A抢到了锁,开始更新。
  • B发现锁被人抢走了,进入等待队列。
  • A更新完成,释放锁,传递消息给等待队列。
  • B因为是等待队列里第一名,所以抢到锁,开始更新。

标签:无锁,CAS,void,private,并发,线程,AtomicInteger,有锁,public
来源: https://www.cnblogs.com/caiyiyang/p/14863326.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有