创建线程(三种方法)

多继承 有无返回值 实现方式 创建方法 启动线程
实现Runnable接口 Y 重写run方法 RunableTask task = new RunableTask() new Thread(task).start();
继承Tread类 N 重写run方法 MyThread thread=new MyThread(); thread.start();
实现Callnable Y 重写call方法 FutureTask futureTask = new FutureTask<>(new CallerTask); new Thread(Futuretask).start();

线程通知和等待(wait、notify、notifyAll)

wait()

线程被阻塞挂起
1、其他线程调用了该共享对象的的notify()或notifyAll()方法。
2、其他线程调用了该线程的interrupt()方法,该线程抛出interruptedException异常返回。
事先要获取监视器锁,否则会抛出IllegalMonitorStateException。

wait(int timeout)

一个线程被挂起,没有在指定时间被另一个线程调用该共享变量的notify()或notigyAll(),该函数还是会因为超时而返回。

notify()

随机唤醒一个wait()的线程
线程唤醒后要跟其他线程竞争监视器锁
事先要获取监视器锁,否则会抛出IllegalMonitorStateException。

notifyAll()

唤醒所有wait挂起的线程

等待线程执行终止(join)

join方法是Thread类直接提供的,无参且返回值为void

线程A调用线程B的join方法后会被阻塞,当其他线程调用了线程A的interrupt()方法中断了线程A时,线程A会抛出InterruptedException异常而返回

线程睡眠(sleep)

Thread类里面的静态方法

当一个执行中的线程调用了Thread的sleep方法后,调用线程会暂时让出指定时间的执行权,也就是在这期间不参与CPU的调度,但是该线程所拥有的监视器资源,比如锁还是持有不让出的。指定的睡眠时间到了后该函数会正常返回,线程就处于就绪状态,然后参与CPU的调度,获取到CPU资源后就可以继续运行了。

当一个线程处于睡眠状态时,如果另外一个线程中断了它,会在调用sleep方法处抛出异常。

让出CPU执行权(yeild)

Thread类的静态方法

当一个线程调用yield方法时,当前线程会让出CPU使用权,然后处于就绪状态,线程调度器会从线程就绪队列里面获取一个线程优先级最高的线程,当然也有可能会调度到刚刚让出CPU的那个线程来获取CPU执行权。

线程中断(interrupt)

方法 作用
void interrupt 中断线程
boolean isinterrupted() 检测当前线程是否被中断
Boolean interrupted() 检测当前线程是否被中断(static方法、发现线程被中断会清除中断标志)

线程的上下文切换

CPU资源分配采用时间片轮转策略
线程上下文切换时机有:
1、当前线程的CPU时间片使用完处于就绪状态时
2、当前线程被其他线程中断时。

线程死锁

为什么会形成死锁?

两个或两个以上的线程在竞争资源的过程中造成的相互等待的现象。
死锁产生的四个条件:
1、互斥条件:线程对已经获得的资源进行排他性使用,即该资源同时只由一个线程占用
2、请求并持有条件:指一个线程已经持有资源,并提出新的资源请求,而新资源已经被其他线程占有,当前线程会阻塞,但并不释放自己已经获得的资源。
3、不可剥夺条件:线程获得的资源不能由其他线程抢占,只能自己执行完了进行释放。
4、环路等待条件:存在线程-资源的环形链

如何避免死锁?

至少要破坏一个死锁产生的条件,其中,只有条件2和4能被破坏。
资源申请的有序性

用户进程Vs守护进程

守护进程是否结束不影响JVM的退出。

并发Vs.并行

并发 同一个时间段内多个任务同时都在执行,并且都没有执行结束
并行 在单位时间内多个任务同时在执行

并发任务强调在一个时间段内同时执行,而一个时间段由多个单位时间累积而成,所以说并发的多个任务在单位时间内不一定同时在执行。

并发(单CPU例子):
image.png
并行:
image.png