Process和Thread
进程是资源分配的单位,线程是CPU调度和执行的单位。一个进程中至少有一个线程。
真正的多线程指的是多个cpu,即多核,而模拟出来的多线程是时间片轮转下的多线程。
Java创建线程三种方式
初学者多用前两种:
- 继承Thread类,有局限性,因为一个类只能继承一个类,但能实现多个接口;子类继承Thread类后,创建对象,调用start方法;
- 实现Runnable接口,方便同一个对象被多个线程使用;
- 实现Callable接口。
静态代理
真实对象和代理对象实现同一个接口
代理对象代理真实对象
代理用来增强,做真实对象做不了的事。
线程五大状态
创建状态、就绪状态、阻塞状态、运行状态、死亡状态
new(),进入创建状态;
start(),等待CPU调度,但不代表立即调度执行,进入就绪状态;
sleep(),wait()或同步锁定时,进入阻塞状态,阻塞事件解除,进入就绪状态;
线程中断或结束,进入死亡状态,不能再次启动。
线程方法
线程停止
不推荐JDK提供的stop()、destory()方法
推荐线程自己停下来(不建议死循环)
建议使用一个标志位进行终止变量当flag=false,则终止线程运行
public class TestStop implements Runnable{
private boolean flag = true;
@Override
public void run(){
while(flag){
//线程具体干的事
}
}
public void stop(){
this.flag = false;
}
}
Sleep()常用作用
1.模拟网络延时,放大问题发生性
2.倒计时
sleep不会释放锁
yield()
1.线程礼让,让当前线程暂停,但不阻塞
2.将线程从运行状态转为就绪状态
3.让CPU重新调度,礼让不一定成功,看CPU心情
join()
合并线程,待此线程执行完后,再执行其他线程
可以想象成插队
Thread.State
线程状态。线程可以处于以下状态之一:
NEW:尚未启动
RUNNABLE:在JAVA虚拟机中执行的线程处于此状态
BLOCKED:被阻塞等待监视器锁定的线程处于此状态
WAITING:正在等待另一个线程执行特定动作的线程处于此状态
TIMED_WAITTING:正在等待另一个线程执行动作达到指定等待时间的线程出于此状态
TERMINATED:已退出的线程处于此状态
线程优先级
范围1-10
getPriority()和setPriority(int xxx)
ArrayList()
线程不安全,可用线程安全的集合CopyOnWriteArrayList()
synchronized与Lock对比
- Lock是显式锁,手动开启和关闭,sychronized是隐式锁,出了作用域自动释放;
- Lock只有代码块锁,sychronized有代码块锁和方法锁;
- 使用Lock锁,性能更好,子类更多(用过ReentrantLock)
- 优先使用顺序
Lock > 同步代码块(进入了方法体,分配了相应资源) > 同步方法(方法体之外)
线程间通信
- wait()表示线程一直等待,会释放锁,这点和sleep()不同;
- wait(long timeout)指定等待的毫秒数;
- notify()唤醒处于等待的线程;
- notifyAll()唤醒同一个对象上所有调用wait()方法的线程,优先级高的线程优先调度。
生产者消费者 - 缓冲区法,缓冲区剩余容量判定是否push或pop
- 信号灯法,用一个boolean标志符判定
线程池
ExecutorService:真正的线程池接口,常见子类ThreadPoolExecutor
- void execute(Runnable command):执行任务/命令,没有返回值,一般用来执行Runnable
- Futuresubmit(Callabletask):执行任务,有返回值,一般又来执行Callable
- void shutdown():关闭连接池
Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池
sleep()和wait()
- 来自不同的类,wait => Object sleep =>Thread
- 关于锁的释放,wait会释放锁,sleep抱着锁睡觉,不释放;
- 使用的范围:
wait必须在同步代码块中,sleep可以在任何地方睡。
简单记:一个人啥时候都能睡,等一个人就不一样了;
Synchronized和Lock区别
- synchronized 是内置的Java关键字,Lock 是一个Java类;
- synchronized 无法判断获取锁的状态,Lock 可以判断是否获取到了锁;
- synchronized 会自动释放锁(a–b),Lock锁必须要手动释放锁!如果不释放锁,死锁;
- synchronized 线程1(获得锁,阻塞)、线程2(一直等待);Lock锁不一定等待下去
- synchronized 可重入锁,不可以中断的,非公平; Lock,可重入锁,可以判断锁,非公平(可以自己设置)
- synchronized 适合锁少量的代码同步问题,Lock 适合锁大量的同步代码
线程可以被唤醒,而不会被通知,中断或超时,即所谓的虚假唤醒。等待应该总是出现在循环中,防止虚假唤醒问题。
tips: 如果采用if判断,当线程从wait中唤醒时,那么将直接执行处理其他业务逻辑的代码,但这时候可能出现另外一种可能,条件谓词已经不满足处理业务逻辑的条件了,从而出现错误的结果,于是有必要进行再一次判断
通过Lock实现生产者消费者
传统版:synchronized、wait、notify
JUC版:Lock、await、signal
Condition优势:
精准通知和唤醒线程,让线程有序执行