线程安全
Posted yidiandhappy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程安全相关的知识,希望对你有一定的参考价值。
再写一个关于线程安全的,很多人都喜欢讨论多线程怎么使用,什么AQS、CAS、对象监视。但是如果线程安全的基本定义没有完全搞清楚的话,多线程用起来还是有点儿可怕的。
什么是线程安全
官方一点儿的说法,多个线程要同时修改一个变量时,要保证一个变量的原子性、可见性、有序性。其实说白了就是,多个线程修改,你要保证每个线程的修改都是对的(等于没说,好像)。
首先,为什么会有线程不安全呢?这是由jvm自身的特性决定的,jvm中有主内存和线程本地内存(线程栈)之说,每一个线程在修改变量的值的时候,都得先去主内存中将该变量拷贝到线程栈里面然修改,然后将修改后的值再同步到主内存中。
举个例子:比如说我们现在在卖周杰伦演唱会的门票,门票剩余五万张,我们采用多线程去做卖票这个事儿,票的剩余数量ticketsCount现在剩余50000,我们开了35个线程同时卖票,这时候可能35个线程都要去修改这个剩余票数,那怎么做呢?
1、从主内存中读取剩余票数,50000
2、在线程栈中修改票数,做减一操作,49999
3、将修改后的票数49999刷回主内存
这就出问题了,其实我们卖了多少呢?35张,可是剩余票数还有49999张,出问题了,超卖!这就是典型的线程不安全问题。
那怎么解决呢?有很多种方法
1、采用原子类,juc中给我们提供了很多基础类型的线程安全版本,如int 的线程安全类AtomicInteger、long的AtomicLong、AtomicBoolean等,在修改这种类型的变量时无需考虑原子性、可见性问题,但线程的修改顺序需要你自己去控制。
2、采用Lock,李叔在juc中也给我们提供了很多的线程安全的辅助类,ReentranLock、ReentranReadWriteLock、Semaphore等控制可见性、原子性、有序性的工具类,来帮助我们实现线程安全。这种的其实又牵扯到AQS,各种的BlockQueue、LeaderFlowller模式等,很多东西,而且特别厉害。
3、利用jvm自身的线程安全机制,如Synchronized,甚至是LockSupport中的park unpark方法,但是LockSupport还是慎用。Synchronized的其实就是java的对象监听器、mointorEnter、monitorExit等
现在都不是单节点部署了,那再集群状态下也会遇到线程安全问题,那怎么办呢?有人说用数据库的事务做并发控制,这种其实是比较奢侈的,因为都知道数据库是昂贵资源,这时候一般都是分布式锁,分布式锁有很多,我先吃饭了。。。一会儿写
以上是关于线程安全的主要内容,如果未能解决你的问题,请参考以下文章