多线程原理
为什么需要多线程?
CPU/内存/IO的巨大性能差异
多核CPU的发展
一个线程表现的本质就是多出来一套完整的方法栈
- 优点:多个执行流,并发执行
- 缺点:
- 占用资源:每个线程有独立的方法栈
- 慢,切换上下文
- 能不能让上下文切换尽可能少?
- 协程 - 用户态线程
Thread
- Thread类的每一个实例代表一个JVM中的线程
只有Thread是线程,其他的都不是线程(注释中提到),Runnable和Callable是一个任务,一小段代码
Runnable / Callable
- Runnable代表一个任务
- 可以被任何一个线程执行
- Callable解决了Runnable的一些问题
- Runnable不能返回值
- Runnable不能抛出checked exception
Runnable jdk1.0
Callable jdk1.5
笔记
多线程缺点:
- 代码复杂,变得很难理解
- 线程的互相交互和访问共享变量会引发各种问题,包括死锁等
try-catch只会捕获当前线程的异常
异常的抛出是顺着方法栈往外抛的
线程的底部要么是main()方法,要么是Thread.run()方法
“在可计算性理论里,如果一系列操作数据的规则(如指令集、编程语言、细胞自动机)可以用来模拟单带图灵机,那么它是图灵完备的。
- 当两个线程运行的时候,方法栈的所有东西都是私有的,其他的都是公有的。
Volatile
- 线程模型:
每一个线程可以有一个主内存的变量的副本,cpu定期同步回内存。
volatile的保证
- 可见性,并非原子性
- 写入volatile变量会直接写入主内存
- 从volatile变量读取会直接读取主内存
- 非常弱的同步机制
- 禁止指令重排
- 编译器和处理器都可能堆指令进行重排,导致问题
- 有同步的时候无需volatile
- synchronized/Lock/AtomicInteger
JUC:java.util.concurrent 并发工具包
- 同步:synchronized
- 协同:wait() / notify() / notifyAll()
synchronized
synchronized
- Java语言级的支持,1.6之后性能及大提高
- 字节码层面的实现:monitorenter / monitorexit
- 锁住的是?
- 对象
- 如果是静态方法,那么锁住的是该类的class
- 如果是非静态方法,那么锁住的是this对象
- Java语言级的支持,1.6之后性能及大提高
缺点
死板。比如:不能查看是否有别人拿到了锁对象。
只有悲观锁、排他锁,没有乐观锁、共享锁
一定要和一个对象(monitor,监视器)协同
面试题:wait和sleep有什么区别?
- wait() 之后锁对象就会被释放
- 如果已经获取了锁对象,那么sleep() 之后不会释放锁对象。如果没获取锁对象,那么不关sleep() 什么事。。。