Atomic、ThreadLocal、Volatile、synchronized总结

Atomic、ThreadLocal、Volatile、synchronized总结

多线程安全:
三个独立的功能——原子性、可见性和顺序性

Atomic:
原子操作:
它会在这步操作都完成情况下才允许其它线程再对它进行操作,这个实现是通过Lock-Free原子操作指令来确定的
Atomic原子操作类,Java的concurrent并发包中几个常用原子操作类AtomicInteger、AtomicLong、AtomicBoolean、AtomicReference:
1、原子操作类,在多线程并发操作同一个资源的情况下,使用Lock-Free算法来替代锁,其开销小、速度快,
2、对于原子操作类是采用原子操作指令实现的,从而可以保证操作的原子性
Atomic原子操作类采用Lock-Free算法替代锁+原子操作指令实现并发情况下资源的安全、完整、一致性

Lock-Free算法,是一种新的策略替代锁来保证资源在并发时的完整性的,Lock-Free的实现有三步:
1、循环(for(;;)、while)
2、CAS(CompareAndSet)
3、回退(return、break)

AtomicInteger类中:
public final int incrementAndGet() {
   for(;;) { // 循环
      int current = get();
      int next = current + 1;
      if(compareAndSet(current, next)) // CAS
        return next; // 回退
   }
}

示例:

public class Counter {
    private AtomicInteger count = new AtomicInteger();
    public int getCount() {
        return count.get();
    }
    public void increment() {
        count.incrementAndGet();
    }
}

在每个线程中通过increment()来对count进行计数增加的操作,或者其它一些操作。这样每个线程访问到的将是安全、完整的count。

synchronized
使用synchronized时,多线程内存模型:
这里写图片描述
同步锁,是Lock的一个简化版本:其内部实现是重入锁ReentrantLock+一个Condition(Lock的简化版本,因为一个Lock往往可以对应多个Condition)
能够保证在同一时刻最多只有一个线程执行该段代码,synchronized实现内存同步(一致性),线程互斥(互斥性)

Volatile
使用volatile时,多线程内存模型:
这里写图片描述
它可以在多线程并发的情况下保证变量的“可见性”
可见性:
就是在一个线程的工作内存中修改了该变量的值,该变量的值立即能回显到主内存中,从而保证所有的线程看到这个变量的值是一致的。
volatile变量放在主存区上,使用该变量的每个线程,都将从主存区拷贝一份到自己的工作区上进行操作,Java内存模型负责各个线程的工作区与主存区的该字段的值保持同步,即一致性
volatile是内存同步,开销比synchronized小、使用成本更低
Volatile关键字可以解决多线程环境下的同步问题,不过这也是相对的,因为它不具有操作的原子性,也就是它不适合在对该变量的写操作依赖于变量本身自己,
实际应用需配合synchronized使用以实现线程的同步、互斥,如:

public class Counter {
    private volatile int count;
    public int getCount(){
        return count;
    }
    public synchronized void increment(){
        count++;
    }
}

ThreadLocal:
ThreadLocal与Thread的联系图:
这里写图片描述
不是解决资源共享的问题,而是用来提供线程内的局部变量,这样每个线程都自己管理自己的局部变量,别的线程操作的数据不会对我产生影响,互不影响,ThreadLocal是自己管理自己的资源,相当于封装在Thread内部了,供线程自己管理
ThreadLocal会为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本,ThreadLocal用于线程间的数据隔离。
ThreadLocal内部有一个静态类ThreadLocalMap,使用到ThreadLocal的线程会与ThreadLocalMap绑定,维护着这个Map对象,而这个ThreadLocalMap的作用是映射当前ThreadLocal对应的值,它的key为当前ThreadLocal的弱引用:WeakReference
ThreadLocal易出现内存泄漏,避免内存泄露:
1、ThreadLocal要设为static静态的
2、在线程不使用它的值时手动remove掉该ThreadLocal的值
示例:

public class ThreadLocalTest {
    //通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值  
    private static ThreadLocal<Integer> idNum = new ThreadLocal<Integer>(){ //ThreadLocal<T> 泛型类,每个线程都能保持一个整型的idNum对象
        @Override
        protected Integer initialValue() {
            return 0;
        }
    };
    static class RunnableT implements Runnable{
        private int num;
        public MyRunnable(int num){
            this.num = num;
        }
        @Override
        public void run() {
            idNum.set(num);
            System.out.println("num: "+idNum.get());
        }
    }

    public static void main(String[] args){
        new Thread(new RunnableT(1));
        new Thread(new RunnableT(2));
    }
}

多线程资源共享:
1、synchronized:简单锁机制实现内存同步(一致性),线程互斥(互斥性),同步机制采用了“以时间换空间”的方式:访问串行化,对象共享化。同步机制是提供一份变量,让所有线程都可以访问。
2、Atomic:通过原子操作指令+Lock-Free完成,从而实现非阻塞式的并发问题。
3、Volatile:内存同步(具有可见性,不具有操作的原子性),在非依赖自身的操作的情况下,对变量的改变将对任何线程可见。
synchronized比volatile对资源的消耗稍微大点,但可以保证变量操作的原子性,保证变量的一致性,最佳实践则是二者结合一起使用
多线程资源独享:
4、ThreadLocal:用来提供线程内的局部变量,ThreadLocal采用了“以空间换时间”的方式:访问并行化,对象独享化。ThreadLocal是为每一个线程都提供了一份独有的变量,各个线程互不影响

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值