做到线程安全,需要注意的几点~

线程安全在三个方面体现:

  • 原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作,(atomic,synchronized);
  • 可见性:一个线程对主内存的修改可以及时地被其他线程看到,(synchronized,volatile);
  • 有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序,(happens-before原则)。

保障原子性动作:

1、synchronized 关键字

     用来控制线程同步的,保证我们的线程在多线程环境下,不被多个线程同时执行,确保我们数据的完整性,使用方法一般是加在方法上。

缺点:效率较低

原理:保证方法或者代码块在运行时,同一时刻只有一个方法可以进入到临界区,同时它还可以保证共享变量的内存可见性。操作的对象头中的mark word(在JVM中,对象在内存中的布局分为三块区域:对象头、实例变量和填充数据,具体实现可以再做探究)

Java中每一个对象都可以作为锁,这是synchronized实现同步的基础:

  • 普通同步方法,锁是当前实例对象。修饰实例方法
  • 静态同步方法,锁是当前类的class对象。比如单例,锁的class
  • 同步方法块,锁是括号里面的对象

2、Lock 类

它跟synchronized有什么区别:

      synchronized无法获取锁的状态,可以自动释放锁,会出现一直等待情况阻塞线程。不可中断,线程原子性。非公平。适合少量代码的同步

      Lock可以判断是否获取到锁,手动释放锁,lock会尝试获取,获取不到就结束。适合大量同步代码

      Lock是在Java1.6被引入进来的,Lock的引入让锁有了可操作性(lock,unlock。tryLock),就是我们在需要的时候去手动的获取锁和释放锁,甚至我们还可以中断获取以及超时获取的同步特性,但是从使用上说Lock明显没有synchronized使用起来方便快捷。

      (补充)ReentrantLock 重入锁类:可以对获取锁的时间做设置,获取各种锁的信息,灵活地实现多路通知。调用的是UNsafe的park方法加锁

3、atomic 

Atomic包中的类基本的特性就是在多线程环境下,当有多个线程同时对单个(包括基本类型及引用类型)变量进行操作时,具有排他性,即当多个线程同时对该变量的值进行更新时,仅有一个线程能成功,而未成功的线程可以向自旋锁一样,继续尝试,一直等到执行成功。

核心类:Unsafe类,包含大量对C代码的操作,包括很多直接内存分配以及原子操作的调用。非安全的。

4、ThreadLocal 类(保证数据安全,区别前三个)

      关于创建线程局部变量的类,使用ThreadLocal创建的变量只能被当前线程访问,其他线程则无法访问和修改为每个线程提供局部变量,解决线程安全问题,ThreadLocal 底层采用 Map 来实现,将当前线程作为key,将值存储到这个 map 中。在Android中,Looper类就是利用了ThreadLocal的特性,保证每个线程只存在一个Looper对象。(每个looper对应一个线程)

实现步骤:

  • 首先获取当前线程
  • 利用当前线程作为句柄获取一个ThreadLocalMap的对象
  • 如果上述ThreadLocalMap对象不为空,则设置值,否则创建这个ThreadLocalMap对象并设置值

存放位置:在Java中,栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。而堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问

保障可见性/有序性动作:

1、volatile 修饰符

原理:在 Java 中为了加快程序的运行效率,对一些变量的操作通常是在该线程的寄存器或者 CPU 缓存中进行的,之后才会同步到主存,而加了 Volatile 关键字后会直接读写内存。多线程做修改操作时,首先从主内存中拷贝一份副本到本地内存中,当线程修改本地内存的值后,首先在本地内存修改成功,然后再将修改后的结果刷新到主内存中

注意:虽然该关键字能够保证可见性,但不能保证原子性特性。

作用:

  • 保证可见性,有序性
  • 禁止指令重排(CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理),使用Volatile 修饰的变量,赋值后多执行了一个"load addl $0x0, (%esp)"操作,这个操作相当于一个内存屏障(指令重排序时不能把后面的指令重排序到内存屏障之前的位置),只有一个CPU访问内存时,并不需要内存屏障。

区别:Synchronized 防止多个线程执行同一块代码,影响执行效率,就性能而言,Volatile 是高于 Synchronized 的。

猜你喜欢

转载自blog.csdn.net/guoyingmiss/article/details/110533411