基本概念
- 进程里的最小执行单元就是线程。
- 实现方式extends Thread , implements Runnable (包括lambda表达式),此外可能还有一种说法还有线程池,但实际上也是前面两种实现之一。
- CPU没有线程概念,其只是不断循环读取内存中的指令并执行。
- 主要方法sleep(),yield(),join()等。
- 线程状态迁移
- 线程状态小demo
public class Test {
static class TestThreadState extends Thread{
@Override
public void run() {
System.out.println(this.getState()); //RUNNABLE,运行
for (int i = 0 ; i < 10; i++){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}
}
public static void main(String[] args) {
TestThreadState thread = new Test.TestThreadState();
System.out.println(thread.getState()); //NEW,创建
thread.start();
try {
thread.join(); //等待TestThreadState线程执行完毕
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(thread.getState()); //TERMINATED,结束
}
/*输出结果:
NEW
RUNNABLE
0
1
2
3
4
5
6
7
8
9
TERMINATED
*/
}
synchronized
http://me.heawill.top/archives/%E7%BA%BF%E7%A8%8B%E4%B8%8E%E5%B9%B6%E5%8F%91synchronized
Volotile
http://me.heawill.top/archives/%E7%BA%BF%E7%A8%8B%E4%B8%8E%E5%B9%B6%E5%8F%91volotile
ReentrantLock与ReadWriteLock
CAS
http://me.heawill.top/archives/%E7%BA%BF%E7%A8%8B%E4%B8%8E%E5%B9%B6%E5%8F%91cas
乐观锁和悲观锁
Phaser 相位器
用来解决控制多个线程分阶段共同完成任务的情景问题
具体用法见:
https://blog.csdn.net/u010739551/article/details/51083004
Semaphore 信号量
如果线程要访问一个资源就必须先获得信号量,具体看:
https://www.cnblogs.com/wxgblogs/p/5422508.html
Exchanger 交换器
可用于两个线程之间交换信息,具体看:
https://blog.csdn.net/octopusflying/article/details/80634864
LockSupport
用来堵塞/唤醒线程,具体看:
https://blog.csdn.net/xiaojin21cen/article/details/89918443
https://segmentfault.com/a/1190000015562456
unpark可以优于park执行,后面的park则不会堵塞。
ThreadLocal
threadlocal而是一个线程内部的存储类,可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据。
spring的@Transactional跟ThreadLocal有关。
ThreadLocal的set方法实际是把ThreadLocal.this这个对象,和set时传入的对象,put到Thread对象里面维护的一个map上(ThreadLocal.this先Entry进行弱引用)。
要及时使用remove(),防止内存泄漏。
https://www.jianshu.com/p/3c5d7f09dfbd
import java.util.concurrent.TimeUnit;
public class Test {
static ThreadLocal<Object> tl = new ThreadLocal<>();
public static void main(String[] args){
new Thread(new Runnable() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
tl.set(new Object());
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(tl.get());
}
}).start();
}
/* 打印
null
*/
}
扩展
set加锁,get不加锁
对某个数据,set加锁,get不加锁,主要看业务逻辑能否允许这种情况(脏读)的出现,如果无脑的get也加锁,会影响读取速度。
参考
多线程高并发详解(马士兵)
https://www.bilibili.com/video/BV1UK411F7YU?p=1
java的可重入锁用在哪些场合?
https://www.zhihu.com/question/23284564
究竟什么是可重入锁?
https://blog.csdn.net/rickiyeat/article/details/78314451
既然CPU有缓存一致性协议(MESI),为什么JMM还需要volatile关键字?
https://www.zhihu.com/question/296949412?sort=created
Readwritelock和lock究竟有什么区别?
https://www.zhihu.com/question/31569596/answer/216247362
计算机缓存Cache以及Cache Line详解
https://blog.csdn.net/qq_21125183/article/details/80590934
https://www.jianshu.com/p/d1ead3a404f4
https://www.cnblogs.com/dongguol/p/6073815.html
http://ifeve.com/writecombining/#more-5087