Thread API(二)

本文深入探讨Java中线程的中断机制,包括interrupt()方法的使用,可中断方法如sleep()、join()和wait()如何响应中断信号,以及如何通过interrupted()和isInterrupted()方法检查线程中断状态。同时,文章提供了实用的代码示例,展示了如何优雅地关闭线程,避免使用已弃用的stop()方法。

interrupt
线程在调用可中断方法进入阻塞时,可由其他线程调用interrupt()进行打断,打断的线程并不是生命周期结束,而是打断当前的阻塞状态。线程调用可中断方法进入阻塞状态下被打断会抛出InterruptedException异常,interrupt标识会被清除。

  	public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // Just to set the interrupt flag
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }

可中断方法
Object 的wait()
Thread 的 sleep()
Thread 的 join()
InterruptibleChannel 的io操作
Selector 的 wakeup()等

线程打断阻塞测试

	Thread t = new Thread(()->{
			try {
				TimeUnit.MINUTES.sleep(1);
			} catch (InterruptedException e) {
				System.out.println("休眠被打断");
			}
		});
		t.start();
		TimeUnit.MILLISECONDS.sleep(2);
		t.interrupt();

输出 休眠被打断

isInterrupted
判断当前线程是否中断,不影响标识状态。
测试1:

	Thread t = new Thread(()->{
			while(true) {
				
			}
		});
		//设置卫守护线程  不然线程不会终止
		t.setDaemon(true);
		t.start();
		System.out.println("Thread is Interrupted  "+t.isInterrupted());
		TimeUnit.MILLISECONDS.sleep(2);
		t.interrupt();
		System.out.println("Thread is Interrupted  "+t.isInterrupted());

输出
Thread is Interrupted false
Thread is Interrupted true

测试2:

	Thread t = new  Thread() {
			@Override
			public void run() {
				try {
					TimeUnit.MINUTES.sleep(1);
				} catch (InterruptedException e) {
					System.out.println("I am  Interrupted  "+isInterrupted());
				}	
			}
		};
		//设置卫守护线程  不然线程不会终止
		t.setDaemon(true);
		t.start();
		TimeUnit.MILLISECONDS.sleep(2);
		System.out.println("Thread is Interrupted  "+t.isInterrupted());
		t.interrupt();
		TimeUnit.MILLISECONDS.sleep(2);
		System.out.println("Thread is Interrupted  "+t.isInterrupted());

输出
Thread is Interrupted false
I am Interrupted false
Thread is Interrupted false

从测试1和测试2结果可以看出中断方法捕获到了中断信号之后,会擦除掉interrupt的标识。
interrupted
是一个静态方法,也是用于判断当前线程是否被打断,调用该方法会直接擦除interrupt标识,如果当前线程被打断,那么第一次调用会返还true,并立马擦除interrupt标识,后面的调用到时false,除非中间线程被再次打断。

 	public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }
     public boolean isInterrupted() {
        return isInterrupted(false);
    }

isInterrupted() 方法传入true表示擦除interrupt标识,false不擦除。
测试

		System.out.println("main Thread is Interrupted  "+Thread.interrupted());
		Thread.currentThread().interrupt();
		System.out.println("main Thread is Interrupted  "+Thread.currentThread().isInterrupted());
		
		try {
			TimeUnit.MINUTES.sleep(1);
		} catch (InterruptedException e) {
			System.out.println("捕获中断信号");
		}	

输出
main Thread is Interrupted false
main Thread is Interrupted true
捕获中断信号

根据结果可以发现,如果一个线程设置了interrupt标识,再调用可中断方法会立即中断。
join
join()会使当前线程永远等待下去,直到中间被其他线程中断,或者join的线程执行结束,当前线程才会退出阻塞。可用于多线程查询结果再一起返回结果集。
测试代码

	public static void main(String[] args) throws InterruptedException {
		List<Thread> threads =  new ArrayList<Thread>();
		threads.add(creat("线程1"));
		threads.add(creat("线程2"));
		//启动线程
		threads.forEach(Thread::start);
		
		for(Thread tt:threads) {
			tt.join();
		}
		for(int i=0;i<3;i++) {
			System.out.println(Thread.currentThread().getName()+"##"+i);
			shortSleep();
		}
	}
	public static Thread creat(String str) {
		return new Thread(()->{
			for(int i=0;i<3;i++) {
				System.out.println(Thread.currentThread().getName()+"##"+i);
				shortSleep();
			}
		},str);
	}
	
	private static void shortSleep() {
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

输出
线程1##0
线程2##0
线程2##1
线程1##1
线程2##2
线程1##2
main##0
main##1
main##2

关闭一个线程
JDK有一个Deprecated方法stop(),该方法在关闭线程时可能不会释放掉monitor锁,所以强烈建议不要使用该方法结束线程。

  1. 可以捕获中断信号关闭线程
    调用 interrupt()或者捕获InterruptedException异常进行处理.
  2. 使用volatile开关控制
    由于线程interrupt标识有可能被擦除,或者逻辑中不会调用中断方法,所以常用volatile修饰的开关关闭线程。
	public static void main(String[] args) throws InterruptedException {
		Task t = new Task();
		t.start();
		TimeUnit.MILLISECONDS.sleep(1);
		t.close();
		System.out.println("shutdown");
	}
	static class Task  extends Thread  {
		private volatile boolean flag =false;
		@Override
		public void run() {
			System.out.println("start work");
			while(!flag && !isInterrupted()) {
				System.out.println("线程正在运行");
			}
		}
		public void close() {
			this.flag=true;
			this.interrupt();
		}
	}

输出
start work
线程正在运行
线程正在运行
线程正在运行
shutdown

  1. 抛出RuntimeException 结束线程生命周期
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值