JAVA多线程
进程与线程区别:进程是资源分配的最小单位,线程是cpu调度的最小单位。
- 进程:进程独占内存资源,保存各自运行状态,相互不干扰且可以相互切换,并为并发任务提供了可能。
- 线程(轻量级进程):共享进程的内存资源,相互切换更迅速,支持更细粒度的任务控制,使进程子任务能并发执行。
发展:串行->批处理->进程->线程
thread与runnable:
关系:thread是实现了runnable接口的类,使得run支持多线程。因为类单继承原因,推荐使用runnable接口。
thread:
- run与start的区别:调用润方法会沿用主线程执行。调用start会生成一个新的子线程。
run方法没有参数,传参方式:1.构造函数。2.成员变量传参set get。3.回调函数传参。
处理线程返回值:
主线程等待法:主线程循环等待,while去无限休眠,只到有返回值(不推荐)
使用join方法:thread.join()阻塞当前线程,以等待子线程吹完毕。缺点是粒度不细
使用callable接口实现,通过FutureTask 或线程池获取。
通过
FutureTask
(包含isDone()阻塞和get()获取值)传入callable
(myCallable implements Callable,任务完成后返回) //返回值类型 String public class MyCallable implements Callable
{ @override public String call(){ return "返回值" } } //调用 FutureTask task=new FutureTask (new MyCallable()); new Thread(task).start(); if(!task.isDone()){ //线程任务未完成 } String str=task.get();//获取返回值 线程池获取:ThreadPoolExecutor推荐使用
ExcutorServices newCachedThreadPool=Excutors.newCachedThreadPool(); FutureTask<String> task=newCachedThreadPool.submit(new MyCallable()); if(!task.isDone()){ //线程任务未完成 } String str=task.get();//获取返回值 newCachedThreadPool.shutdown();//关闭线程池
线程状态:
六个状态:
- 新建new:创建后尚未启动的线程状态。
- 运行runnable:包含running(位于可运行线程之中,等待被线程调度使用获取cpu使用权)和ready(位于线程池中,等待被线程调度使用获取cpu使用权)
- 无限等待waiting:不会分配cpu执行时间,需要被其他线程显式唤醒。
- 没有设置timeout参数的wait()方法;
- 没有设置timeout参数的join()方法;
- LockSpport.park()方法;//工具类
- 限期等待time wait:在一定时间后由系统自动唤醒。
- Thread.sleep()方法;
- 设置timeout参数的wait()方法;
- 设置timeout参数的join()方法;
- LockSpport.parkNanos()方法;//工具类
- LockSpport.parkUntil()方法;//工具类
- 阻塞blocked:等待获取排它锁。//例如synchroned。
- 结束terminated:已终止线程状态,线程已经结束执行。
sleep与wait区别
区别:
- sleep只会让出cpu,不会导致锁行为改变。(只让出锁)
- wait不但让出cpu还会让出已经占有的同步锁资源。(让出cpu和同步锁)
使用范围:
- sleep是Thread类方法,wait是object类中定义方法。
- sleep方法可以任何地方使用。
- wait只能在synchronized方法或块中使用。
final Object lock=new Object();//全局变量 new Thread(new Runnable{ @overide public void run(){ synchronize(lock){ //业务执行 lock.wait(1000);//wait不加时间,就需要->lock.notify()唤醒; //Thread.sleep(1000); } } }).start();
notify与notifyAll区别:
- 先了解两个概念:
- 锁池:假设线程a已经拥有了某个对象的锁,而其他线程b c想要调用这个对象的某个synchronize方法(或块),由于b c线程在进入synchronize方法必须拥有此锁的拥有权,而恰巧该对象锁目前正被线程a占用,此时b c阻塞,进入一个地方等待锁释放,这个地方便是锁池。
- 等待池:假设线程a调用了某个对象的wait()方法,线程a就会释放该对象锁,同时线程a进入到了该对象等待池中,进入到等待池中的线程不会去竞争该对象的锁。
- 区别:
- notifyAll会让所有处于等待池中的线程全部进入锁池去竞争获取锁的机会。没有获取到锁的而已经待在锁池的只能等待其它机会,而不能再回到等待池中。
- notify只会随机选取一个处于等待池中的线程进入锁池去竞争获取锁的机会。
- 先了解两个概念:
yieId函数:
- 当调用yieId函数时,会给线程调度器一个当前线程愿意让出cpu的暗示,但是线程调度器可能会忽略这个暗示(可能会停止线程执行,也可能会让出)
中断线程:
- 调用stop()、supend()、resume()停止线程(抛弃)
- 通过interrupt(),通知该线程中断(线程会自己决定是否中断)
- 如果线程处于阻塞状态,那么线程安静会立刻退出阻塞状态,并且抛出interruptedException错误
- 如果线程处于正常活动状态,那么就会将线程中断标记为true,则线程继续正常运行。
线程状态关系图: