1什么是线程安全:
如果一个对象可以安全的被多个线程同时使用,那他就是线程安全的。
如何实现线程安全:
1.互斥同步。
互斥是方法,同步是目的,互斥同步的主要问题是线程阻塞和唤醒所带来的性能问题,属于一种悲观的并发策略。
实现同步主要有(1)加synchronized (2)重入锁Reentrantlock。
关于synchronized和Renntrantlock的区别
(1).两者都具备线程可重入的,只是代码写法上有区别,一个表现为API原生的互斥(lock和unlock方法配合try/finally语句块来完成),另一个表现为原生语法层面的互斥锁。
(2).Reentrantlock相比synchronized增加了新的高级特性(a.等待可中断b.可实现公平锁c.锁可以绑定多个条件)
2.非阻塞同步
基于冲突检测的乐观并发策略:先进行操作,如果没有其他线程争用共享数据,那操作就成功了,如果共享数据有争用,产生了冲突,就采取其他措施(常见的有不断重试,直到成功。),乐观并发策略需要"硬件指令集的发展"的支持。
关于乐观锁和悲观锁:
悲观锁:总是假设最差的情况,每次操作数据都认为别人会进行修改,所以每次拿数据的时候都会对数据进行加锁,这样别人想拿这个数据就会阻塞直到拿到锁,具体的应用有mysql的行锁,表锁,读锁(别人不能进行写),写锁,java的synchronized和Reentrantlock。适用场景是:多写的场景,因为如果多写的场景用乐观锁的话,比如CAS
java中synchronized和renntrantlock线程阻塞和唤醒涉及到操作系统用户态内核态的切换,浪费cpu资源,而CAS操作基于硬件的实现不需要进入到内核,不需要切换线程,但是如果多写的场景,线程竞争激烈,cas操作会一直等待,直到耗尽cpu分配给该线程时间片,从而降低效率。
乐观锁:总是假设最好的情况,拿数据的时候别人不会修改,但是在更新数据的时候会判断一下在这期间别人有没有更新这个数据,可以使用版本号 和CAS实现,适用的场景:多读少写的场景。