多线程
程序:为了完成某个任务用某种语言编写的指令集合
进程:程序的一次执行过程
线程:cpu调度的最小单位,一个指令流
并行:多个cpu同时执行多个任务
并发:一个cpu同时执行多个任务
创建
继承Tread类
class 类 extends Thread{
public void run(){
线程要执行的任务
}
}
引用 = new 类();
引用.start(); //开启一个线程,只能调用一次
①让线程进入阻塞状态 ②调用run()方法 ③完成run()方法后
引用.run(); //普通方法,不能开启线程
.sleep()让当前线程休眠,进入阻塞状态,休眠时间结束进入就绪状态
实现Runnable接口(没有start()方法)
class ClassName implements Runnable{
public void run(){
线程任务
}
}
ClassName 引用=new ClassName();
Thread thread = new Thread(引用);
thread.start();
implements Runnable的优势:
可以继承其他类,实现多接口。
实现Callable接口
使用方法和Runnable接口类似
Callable接口内的call()方法有返回值
线程的调度模式
cpu给线程分配时间片,得到时间片的线程可以执行,没有得到时间片的线程处于等待状态
Thread1.join()让线程进入阻塞,等待Thread1执行完毕后再进入就绪状态
生命周期
新建:Thread类被创建后,处于新建状态
就绪:处于新建状态的线程对象调用start()方法后,进入就绪状态,等待cpu分配时间片
运行:处于就绪状态的线程得到cpu分配的时间片后进入运行状态
阻塞: 执行某些操作(wait(),sleep(),join()等)后让出时间片并终止任务,进入阻塞状态
死亡:线程对象完成任务或者被强制退出时,进入死亡状态
Thread常用方法
start():启动当前线程并调用run()方法
run():线程需要执行的操作
currentThread():返回执行当前代码的线程
getName():获取当前线程的名字
setName():设置当前线程的名字
yield():主动释放当前线程的时间片,进入就绪状态
join():执行另一个线程,当前线程被阻塞,直到另一个线程执行完毕(死亡)以后,该线程才继续执行
sleep():当前线程临时停止执行设定的毫秒数
isAlive():判断当前线程是否存在
线程安全
synchronized
synchronized(){
同步操作
}
同步代码块:需要同步的代码放在synchronized代码块中
同步方法:用synchronized修饰方法
死锁:
原因:synchronized使用不当,加锁顺序不当
解决:①改变加锁顺序 ②使用Lock锁(手动锁)
lock
接口,实现类Reentrant
lock.lock()加锁
lock.unlock()释放锁
lock.trylock()加锁(成功返回true,失败返回false)
lock.trylock(time,Timeunit)加锁(规定时间内加锁成功返回true,失败返回false)
Synchronize和Lock的区别
- synchronized是关键字,Lock是接口
- synchronize的加锁和释放时自动的,Lock相反
- Lock可以监听锁的状态
- synchronize可能会造成死锁,Lock则不会
线程通信
利用wait()、join()、sleep()方法实现线程之间的交互
notify()唤醒另外一个被wait()的线程
notifyAll()和notify()的区别:
notify唤醒单个线程;notifyAll唤醒所有线程
wait()和sleep()的区别:
sleep不会释放锁,wait会释放锁
sleep时间结束自动唤醒,wait()需要调用notify()手动唤醒
通过锁对象调用wait()、notify()方法
wait()抛出异常InterruptedException