先了解下基本概念。
JMM:
每个线程都有自己的工作内存。即使对于堆中的数据,工作线程也是对工作内存中的数据进行操作,再同步回堆内存。
线程:
5中状态。创建。就绪。运行。阻塞。死亡。
作用:充分利用cpu的资源【因为cpu执行非常的快百亿秒级,一旦io或者其他的情况阻塞,cpu就空闲了,而多线程这时就可以进行切换】。
java中操作线程状态的几个方法:notify,wait,sleep,notifyall。
wait和sleep的区别是:wait会释放锁。
nofity:随机唤醒一个。
锁:
作用:就是解决多线程数据的安全性问题。这也是需要代价的,想要复杂想要高效,就得解决对应产生的问题。
synchronized:底层的实现:每个对象的对象头中都有一个监视器monitor。当使用syn时,会在monitor中保存这个锁的标志,后续的线程再进来发现有该标志了,就阻塞了。简单的说就是sync是jvm通过monitor来实现的。
jdk1.6之后对于sync的优化出现了偏向锁、轻量级锁、重量级锁。大大提升了sync的性能。
偏向锁:没有线程竞争的时候用。解决的问题是,避免了加锁和解锁的性能浪费。
轻量级:少量竞争。解决的问题是线程在用户态和内核态切换的话耗费性能,不如让线程自旋,通过CAS进行锁的获取,在少量竞争的情况下,能够提升性能。【本质:是在cpu空转和线程切换之间做抉择,少量的情况适合cpu空转,因为会马上得到锁,不至于空转很长时间,更划算】
重量级:大量竞争。
CAS: 是jvm本地方法,c++实现,不同的操作系统实现细节不太一样,大概的就是利用cpu级别进行cas操作。特点是原子性。也可以叫做乐观锁。
缺点:1、aba问题;2、cpu空转。【就是在cpu和线程切换之间做选择,根据不同情况做分析】
volatile: 每个线程都有一个自己的本地内存(主内存的备份),volatile关键字保证了变量修改可以被其他线程看到。禁止编译器对指令进行重排。
适用的场景:一写多读的场景。【双重检查单例模式的应用。volatile+ synchronized保证单例的安全和高效。】
ThreadLocal:
需要了解的知识:强弱软虚引用。
每个线程独有。本质是threadlocalmap,key为threadlocal的弱引用。value为存储进去的值。
一个thread一个threadlocalmap。一个map有多个entry.一个entry的key指向一个threadlocal对象。即一个thread线程可以有多个threadlocal对象。
使用时注意事项:因为弱引用的关系,如果没有其他的对threadlocal的引用,会导致线程进行回收key,而value还存在,导致内存泄漏,所以结束的时候要进行remove操作。
线程池
不要采用Excutors的静态方法创建线程池,没有给具体的信息,容易造成oom。
需要采用ThreadPoolExcutors来创建线程池。
JUC
JAVA util Concurrent包。java并发工具包。很关键,很多类都实现了相关的功能,优先使用。直接拿来用就行。