✅有哪些实现线程安全的方案?

典型回答

在编程中,如果遇到并发安全的情况,有哪些方案可以来实现线程安全呢?以下是几个常见的方案(本文没有局限某种编程语言,而是说的整体思想):

1、单线程


想要实现线程安全,最简单的方式就是干脆不支持多线程,只用单线程来执行,那么就可以从根本上杜绝线程安全的问题了。比如Redis,就是这种思想,在命令执行时,只依赖单线程进行。

✅Redis为什么被设计成是单线程的?

2、互斥锁

如果一定要用多线程,比较有效的方式就是排队,那么加锁是一种比较常见的排队方式,无论是synchronized、reentrantLock这种单机锁,还是Redis实现的分布式锁,还是数据库中的乐观锁、悲观锁,本地思想都是通过加互斥锁的方式让多个并发请求排队执行。

✅synchronized和reentrantLock区别?

3、读写分离

除了加锁以外,还有一种做法,那就是读写分离,比如Java并发包中有一种COW机制,即写时复制,主要就是读和写作分离的思想,因为读操作并发是没什么影响的,而写操作的话,只需要让他不发生并发就行了。

比如,CopyOnWriteArrayList使用了一种叫写时复制的方法,当有新元素add到CopyOnWriteArrayList时,先从原有的数组中拷贝一份出来,然后在新的数组做写操作,写完之后,再将原来的数组引用指向到新数组。

✅什么是COW,如何保证的线程安全?

4、原子操作

原子操作是不可中断的操作,要么全部执行成功,要么全部失败。在多线程环境中,可以使用原子操作来实现对共享资源的安全访问,例如Java中的AtomicInteger等操作。

原子操作底层一般都是依赖的操作系统的CAS指令,思想也就是Compare And Swap

✅什么是CAS?存在什么问题?

5、不可变模式

并发问题之所以发生,有个重要原因就是因为有共享变量,试想一下,如果只有读的情况,那么永远也不会出现线程安全的问题,因为多线程读永远是线程安全的,但是多线程读写一定会存在线程安全的问题。

那既然这么说是不是通过只读就能解决并发问题呢?其实最简单的办法就是让共享变量只有读操作,而没有写操作。这个办法如此重要,以至于被上升到了一种解决并发问题的设计模式:不变性(Immutability)模式

✅什么是不可变模式,有哪些应用?

如Java中的String就是不可变模式的一种体现,他的好处就是永远不会出现并发问题。

✅String的设计,用到了哪些设计模式?

6、数据不共享

像前面说的,如果没有共享数据,那么就不会有线程安全问题了,除了不可变模式,还有一种我们常用的手段来避免并发问题。那就是用ThreadLocal

✅什么是ThreadLocal,如何实现的?

原文: https://www.yuque.com/hollis666/xkm7k3/wwsbaz77gvug9hbb