线程安全是什么?
维基百科:线程安全是程序设计中的术语,指某个函数、函数库在多线程环境中被调用时,能够正确地处理多个线程之间的公用变量,使程序功能正确完成。
《Java并发编程实战(Java Concurrency In Practice)》的作者Brian Goetz:当多个线程同时访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那就称这个对象是线程安全的。”
实现线程安全的几种方式
同步的定义:同步是指在多线程环境中,控制多个线程
阻塞同步(悲观)
互斥是方法是手段,同步是目的。
使用
synchronized和ReentrantLock对比:
-
Java语法层面的同步,足够清晰,也足够简单;
-
对开发者要求高,必须要在finally块中释放锁;
-
JVM可以在线程和对象的元数据中记录synchronized中锁的相关信息来进行优化,而Lock不行。
如果synchronized能满足使用需求那就使用synchronized。
ReentrantLock的高级功能:
-
线程阻塞等待时可以中断;
-
可以实现公平锁(在锁被释放时,等待锁的所有线程按照时间顺序来依次获得锁,性能差,吞吐量下降);
-
锁可以绑定多个条件。
-
-
这是一种悲观的策略。不管共享数据有没有出现竞争,都会默认加上锁(不过JDK6下下的synchronized除外,JVM会通过线程和对象的元数据信息优化掉很大一部分不必要的加锁)。主要问题是进行
非阻塞同步(乐观无锁)
硬件层面提供的基于冲突检测的乐观并发策略,通俗地说就是不管共享数据有没竞争,直接操作;如果共享的数据的确出现竞争了,产生了冲突,那再进行其他的补偿措施,最常用的补偿措施是不断地重试,直到出现没有竞争的共享数据为止。
JDK下的Unsafe类中的native方法compareAndSwapInt,其中JUC下的AutomicInteger的incrementAndGet方法就使用到了。
无需同步
可重入代码的确具备上述特征,例如不依赖全局变量、存储在堆上的数据和公用的系统资源,用到的状态量都由参数中传入,不调用非可重入的方法等。因此,如果一个方法的返回结果是可以预测的,只要输入了相同的数据就都能返回相同的结果,那么它就满足可重入性的要求,即使这个方法被多个线程同时调用也不会出现线程安全问题。
可重入代码的另一个重要特征是,当一个线程在执行可重入代码时,它可以被另一个线程中断,并在中断后恢复执行,而不会影响程序的正确性。这是因为可重入代码只依赖于传入的参数和局部变量,它不会修改全局变量和其他线程共享的资源,因此不会对其他线程的执行产生影响。
总之,可重入代码具有预测性和可中断性两个特征,这些特征保证了可重入代码的线程安全性,使得它可以被多个线程同时调用而不会出现数据竞争、死锁等线程安全问题
把共享数据的代码保证在同一个线程中执行。
Java中的实现就是ThreadLocal。一般使用在存储用户数据上下文。
参考:《深入理解Java虚拟机》
标签:重入,同步,Java,synchronized,安全,线程,思考,数据 From: https://www.cnblogs.com/road2master/p/17368305.html