绕不开的多线程

2020-04-12  本文已影响0人  zjp999988

思考比结论重要;

在前面讨论的rpc网络通讯 以及线程池,都涉及了线程的细节问题,

还有经常使用的java集合中jdk为我们分别提供了线程安全和线程不安全的实现;

那就衍生在什么场景下使用不同的实现?

------>这意味着你要区分出什么是线程安全什么又是线程不安全的场景

------>意味着线程安全的根源是什么?都知道线程安全要使用锁syn(结论)

使用锁解决了哪些,有没有带来哪些问题?

接下来几篇会深入讨论多线程和安全问题

看图说话

1.java内存模型,java语法层面为解决多线程提出的jmm模型

由上图可以推理thread1和2如果没有很好的通知机制,1改变了主内存值,没有通知thread2的话主内存和thread中的值就会出现不一致了;

java语法提出了这个问题;最终去去实现的就是jvm;

可以推理如果同一时刻只有一个线程访问,那是不是线程就会安全了;

jvm提供了synchronized的实现,本质上是一个对象监视器;

jdk还有提供提供了基于lock的实现的锁;

ReentrantLock ,ReadWriteLock 本质上也是基于cas操作实现的;

?什么是cas操作

cas是基于硬件级别的同步源语;从硬件级别保证了操作的原子性;

compareAndSwap(旧值,新值)语法是旧值和主内存的值是一致的就可以替换成新值;

这个时候2个线程都想更新到主内,假设线程1更新成功,主内存变为1,线程2对比旧值已经变化,就更新失败,开始自旋转重试;cas保证了多个线程同时更新时的值同步问题;

我们来看下jdk中都有哪些类使用了cas

java.util.concurrent.locks.AbstractQueuedSynchronizer#compareAndSetState

java.util.concurrent.atomic.AtomicInteger#compareAndSet

基本上juc包下都会基于cas;

下面我们来AtomicInteger的cas操作

jdk提供了unsafe操作内存地址的方法,unsafe内jdk中大量使用;

下面看下可见性问题也可以从jmm中发现,thread之间的修改;由于存在缓存在本地,未及时更新到之内存;

那么只要全部基于主内存,没有缓存在本地;或者说只要是写对于读可见就可以解决;

jdk 提供 volatile来解决这个可见性问题;

解决了多线程问题;我们来看下线程的使用方面;

线程如何通讯,有哪些方法?

wait notify park unpark

//使用线程池模型

基于模型使用线程要注意几个核心参数的使用和设置是有不同影响的;

推荐ThreadPoolExecutor 创建线程池;因为参数可以灵活配置

接下来会集中在中间件,只要是网络都会涉及到nio和多线程和netty的身影,前面多线程和NiO要理解好

上一篇下一篇

猜你喜欢

热点阅读