第三章 线程之间的通信
3.1.1 阻塞当前线程
public static void main(String[] args) {
//定义锁
Object o = new Object();
//新建阻塞线程
new Thread(()->{
//新建任务
//循环10次
for (int i=0;i<10;i++){
//打印日志
System.out.println(Thread.currentThread().getId()+",i="+i);
//循环到第5次的时候
if (i==5){
//获取锁
synchronized (o){
//打印日志
try {
System.out.println(Thread.currentThread().getId()+",开始等待...");
//当前线程进入等待
o.wait();
//当前线程进入阻塞
//打印当前线程的状态
}catch (Exception e){
}
}
}
}
//启动这个线程
}).start();
//新建唤醒线程
new Thread(()->{
//新建唤醒任务
//打印日志
System.out.println(Thread.currentThread().getId()+"running...");
//延迟一秒种
try{
//获取锁延迟一秒钟,不然这个线程会抢先执行
Thread.sleep(1000);
synchronized (o){
//打印日志
System.out.println(Thread.currentThread().getId()+",发送notify通知...");
//发送唤醒通知
o.notify();
}
}catch (Exception e){
}
//启动线程
}).start();
}
- 不管调用wait方法还是notify方法,都要先获取锁。总结来说:如果没有锁,线程的执行顺序是不确定的,那么有可能notify线程会优先于wait线程执行,导致wait唤醒失败。
3.1.2 案例分析
3.2 join线程排队
- 线程a调用线程b对象的join方法,会导致线程a的允许中断,知道b运行完毕,线程a才继续运行。(插队)
static class Worker extends Thread{
private UrgentTask joiner;
public void run(){
int i=0;
while (i<9){
try {
if (i == 8){
UrgentTask urgent = joiner;
System.out.println("突然接到了紧急工作,需要去处理");
urgent.start();
urgent.join();
}
//延时加载
TimeUnit.SECONDS.sleep(1);
i+=2;
}catch (InterruptedException e){
e.printStackTrace();
}
}
System.out.println("我已完成了日常工作,完成度100%。。。");
}
public void setJoiner(UrgentTask joiner){
this.joiner = joiner;
}
}
static class UrgentTask extends Thread{
public void run(){
int i=0;
while (i<9){
try {
System.out.println("紧急任务处理,完成度"+(i*10)+"%");
TimeUnit.SECONDS.sleep(1);
i+=3;
}catch (InterruptedException e){
e.printStackTrace();
}
}
System.out.println("紧急任务完成度为"+"100%");
}
}
public static void main(String[] args) {
try {
Worker worker = new Worker();
UrgentTask j = new UrgentTask();
worker.start();
//延时加载
TimeUnit.SECONDS.sleep(3);
worker.setJoiner(j);
}catch (Exception e){
e.printStackTrace();
}
}
3.3线程中断
如果想停止一个正在运行中的线程,可以尝试使用**interrupt()**方法,interrupt()方法并不能马上停止线程的运行,它只是给线程设置一个中断状态值,线程是否能够停止,由操作系统和cpu决定。
3.3.1中断运行态线程
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<10;i++){
if (Thread.currentThread().isInterrupted()){
System.out.println("收到中断通知,结束线程....");
break;
}else {
System.out.println(Thread.currentThread().getId()+",i="+i);
try {
Thread.sleep(100);
}catch (Exception e){}
}
}
}
});
t.start();
try {
Thread.sleep(500);
}catch (Exception e){}
t.interrupt();
System.out.println(t.getId()+"中断状态:"+t.isInterrupted());
}
- 总结:处于waitting阻塞态和休眠阻塞态的线程,调用interrupt()方法会抛出interruptedException异常。
3.4 CountDownLatch计数器
- 用于运行一个或多个线程阻塞等待,直到其他线程工作完毕才开始执行。
3.5 CyclicBarrier屏障
- 屏障能够让所有的并行任务都在CyclicBarrier屏障处停止。