线程进程和程序
程序,指令和数据的文件,静态代码
进程,程序的一次执行过程,系统运行程序的基本单位
线程,操作系统能够进行运算调度的最小单位,一个进程里可以有很多线程
线程优缺点
发挥多核CPU的性能,系统运行更快,AMD,YES!
要内存,有线程安全问题
守护线程
程序完毕,JVM会等待非守护线程完成后关闭,不等待守护线程
线程的生命周期
- 新建 new一个线程
- 就绪 等待被线程调度选中
- 运行 执行任务
- 死亡 执行完毕,或者被kill
- 阻塞 暂停运行,让出CPU
- 睡眠 指定时间过去即可进入就绪状态
- 等待 调用notify方法回到就绪状态
- 挂起 被另一个线程阻塞 调用resume恢复
结束线程
- 退出标志
- 使用interrupt方法
如何实现线程
- 继承 Thread 类创建线程类
- 通过 Runnable 接口创建线程类
- 通过 Callable 和 Future 创建线程
Runnable还是Thread
Runnable
- Java允许调用多个接口,但是只能继承一个类
- Runnable比Tread共享同一个资源更方便
- 可以用线程池
Runnable和Callable
Callable的call方法可以抛出异常
run和start区别
直接调用run不会创建新的线程,普通方法
ThreadLocal
ThreadLocal是每个线程里拥有的自己独立的变量,消除竞态条件
减少对象创建个数
线程安全
一个函数在多线程环境调用时,能正确处理多个线程之间的共享变量,保证程序功能正确完成,就是线程安全的
synchronized
给方法或者代码块加锁,当锁定一个方法时,同一时刻只能有一个线程执行这段代码
Java内存模型
一个处理器有不止一个CPU,两个CPU同时操作一个地址有可能会发生问题,为了保证一个CPU的写入动作对其他CPU是可见的,处理器提供了内存模型
volatile
volatile保证了内存的可见性,避免指令重排。被volatile修饰的变量的下一个读操作必须在前一个写操作之后发生
volatile 和 atomic
volatile只保证先行关系,写操作必须在读操作之前,但是不保证原子性
atomic可以让操作具有原子性
volatile 和 synchronized
- volatile仅能使用在变量级别,synchronized可以使用在变量方法和类级别
- volatile仅能保证可见性,synchronized保证可见性和原子性
- volatile不会阻塞线程
避免死锁
两个线程争夺资源造成互相等待的现象,就叫死锁
阻止循环等待条件,将系统中资源规定按一定顺序申请就可以避免死锁
死锁与活锁的区别
任务执行没有满足某些条件导致一直重复尝试就是活锁
活锁可以自行解开,死锁不能
悲观锁和乐观锁
总假设最差的情况,每次拿到数据都会上锁
默认别人不修改数据,只在更新时判断别人有没有更新,性能好吞吐量高
CAS
Compare and Swap,多个线程同时更新一个变量,只有一个线程更新成功,其他线程失败,失败线程不会被挂起,而是重新去尝试
ReenTrantLock
自旋锁,通过CAS操作加锁,避免线程阻塞的锁