栏目分类:
子分类:
返回
终身学习网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
终身学习网 > IT > 软件开发 > 后端开发 > Java

线程安全的实现方法

Java 更新时间:发布时间: 百科书网 趣学号
1.互斥同步

互斥同步是一种常见也是最主要的并发正确性保障手段,同步是指在多个线程并发访问共享数据时,保证共享数据在同一个时刻只被线程使用。互斥实现方式有互斥量,临界区,信号量等手段。

JAVA里面最常见的互斥同步就是synchronized,synchronized关键字经javac编译后,会在同步块的前后形成monitorenter和monitorexit两个字节码指令。这两个字节码指令都需要一个明确的reference对象来解锁:

对于static方法锁住的是class对象;对于非static方法,锁住的是调用方法的对象,对于synchronized代码块,锁住的是synchronized(obj)中指定的对象

在获取对应的reference对象后,当前线程可以操作同步代码块,若当前线程在持有锁的情况下再次获取锁,会成功,且锁的持有计数会+1,每当释放一次锁,锁的持有计数-1,当锁的持有计数为0时,锁释放,可被其他线程获取。当一个线程持有锁对象时,对于互斥同步,其他线程在获取锁对象失败后,会被阻塞。

从上面的分析可以看出,互斥同步是一个重量级的操作,涉及到用户态与内核态的切换(操作互斥量和阻塞线程需要使用内核态),需要花费大量的时间,对于代码量较小的操作,应对这种重量级操作进行优化。

2.非阻塞同步

互斥同步面临的问题主要是线程阻塞和唤醒所带来的性能开销,因此这种也被称为阻塞同步。而与之对应的就是非阻塞同步。它的主要改进是对于获取锁失败的线程不再将其挂起,而是让其自旋等待一段时间,若还是无法获取锁,则挂起。

设置锁的持有对象也不再需要操作互斥量,而是采用原子操作进行设置,在设置成功后,当前线程获取到锁的对象。而其他线程在原子操作获取锁失败后,会自旋(可以理解为继续走循环尝试继续获取锁)等待,直到获取锁成功,或超过一定次数后被挂起。

但这种方法存在一个漏洞,即ABA问题。具体可以参照下面这几张图。即线程1在进行原子操作时因某些原因被阻塞,此时线程2利用原子操作将目的对象的值改为A,之后线程2又使用原子操作将值改回B,此后线程1突然恢复,再次进行原子操作将值改回A,此时原本应该是B的值变为了A,出现了安全性问题。

 

 

 

3.无同步方案

要保证线程安全,不一定非要用阻塞同步或者非阻塞同步,同步与线程安全两者没有必要的联系。如果一个方法不涉及数据共享,那么不需要任何手段就能保证其线程安全。这种无同步方案主要有两种方式实现。

一是可重入代码(Reentrant Code)。它可以在运行的任何时刻中断,转而去执行另一端代码,而在控制权返回后可以继续执行,原来的程序不会出错,也不会对结果有影响。

二是线程本地存储(Thread Local Storage)。如果一段代码中所需要的数据必须与其他代码共享,那么就看这些共享的数据能否保证在同一个线程中执行,如果能,则无需同步。对于每一个Thread对象,其中都有一个ThreadLocalMap对象,这个对象中,以本地线程变量的hashCode为键,本地线程变量的值为key-value键值对,因而我们可以通过这个ThreadLocalMap对象来找到对应的本地变量的值。

转载请注明:文章转载自 www.051e.com
本文地址:http://www.051e.com/it/273689.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 ©2023-2025 051e.com

ICP备案号:京ICP备12030808号