线程阻塞中断的恢复方式

转载自(https://blog.csdn.net/u013851082/article/details/69524861)
1、线程阻塞
一个线程进入阻塞状态可能的原因:
①通过调用sleep(millseconds)使任务进入休眠状态;
class Demo1 implements Runnable throws InterruptedException{
public void run(){
Thread.sleep(1000);
}
}
②通过调用wait()使线程挂起,直到线程获取notify()/notifyAll()消息,(或者在Java SE5中java.util.concurrent类库中等价的signal()/signalAll()消息),线程才会进入就绪状态;
class Demo2 implements Runnable{
public void run(){
Thread.await();
Thread.notify();
}
}
③任务在等待某个输入 / 输出流的完成;
class Demo3 implements Runnable throws InterruptedException{
private InputStream in;
public void run(){
in.read();
}
}
④任务试图在某个对象上调用其同步控制方法,但是对象锁不可用,因为另一个任务已经获取了该锁;
class Demo4 implements Runnable{
public synchronized void method1(){ }
public synchronized void method2(){ }
public void run(){
method1();
}
}


2、线程中断的方法
Thread类包含interrupt()方法,用于终止阻塞任务;

1)中断①②类线程休眠,挂起阻塞的方法
1.直接使用Thread.interrupt();
main(){
Thread t = new Thread(new Demo1());
t.interrupt();
}
2.使用Executor线程池,中断线程池中的所有线程;
main(){
ExecutorService exec = Executors.newCachedThreadPool();
for(int i=0;i<5;i++)
exec.execute(new Demo1())
exec.shutdownNow();
}
3.使用Executor线程池,中断线程池中单个阻塞的线程;
main(){
ExecutorService exec = Executors.newCachedThreadPool();
Futrue<?> f = exec.submit(new Demo1());
f.interrupt();
}

//中断后的清除代码放置在InterruptedException异常的catch捕获的代码块中


2)中断③类I/O阻塞的方法
使用Thread.iterrupt方法无法中断I/O阻塞,这对于基于Web的程序是很不利的;
①有一种解决方法:关闭任务在其上发生阻塞的底层资源;
main(){
ExecutorService exec = Executors.newCachedThreadPool();
ServerSocket server = new ServerSocket(8080);
InputStream socketInput = new Socket("localhost",8080)
exec.execute(socketInput);
exec.execute(Sytsem.in);
//exec.shutdownNow(); 无法中断2个线程;

socketInput.close();
in.close();
exec.shutdownNow();
}

②java.nio类库提供了更加人性化的I/O中断,被阻塞的nio通道会自动地响应中断;
class Demo impelenets Runnable{
private final SocketChannel sc;
public Demo(SocketChannel sc){ this.sc = sc;}
public void run(){
try{
sc.read(ByteBuffer.allocate(1));
}catch(CloseByInteruptedException e1){
}catch(AsyncronousCloseException e2){
}catch(IOException e3){
}
}
}
public Test {
public static void main(){
ExecutorService exec = Executors.newCachedThreadPool();
ServerSocket server = new ServerSocket(8080);
InetSocketAddress isa = new InetSocketAddress("localhost",8080);
SocketChannel sc1 = new SocketChannel.open(isa);
SocketChannel sc2 = new SocketChannel.open(isa);

exec.execute(new Demo(sc1));
Future<?> f = exec.submit(new Demo(sc2));
f.cancel(true); //可以终止sc1通道所在的线程;
exec.shutdownNow(); //可以终止exec线程池内所有的线程;
sc1.close();
sc2.close();
}
}

3)中断④类被互斥阻塞的线程
使用Thread.iterrupt方法无法中断互斥类线程,
解决方式1:可以使用ReentrantLock显式加锁,在JavaSE5中引入的新特性,ReentrantLock上阻塞的任务可以被中断;
class Task imlements Runnable{
private Lock lock = new ReentrantLock();
public void run(){
lock.lock();
try{
while(true)
}catch(InterruptedExcpetion e){
System.out.println("The Task is interrupted!");
}finally{
lock.unlock();
}
}
public void main(){
Thread t = new Thread(new Task());
t.start();
t.interrupt();
}
}


解决方式2:使用一个while(!Thread.interrupted())包裹同步的代码块
class Task impelments Runnable{
private synchronized void method1(){ }
public void run(){
try{
whlie(!Thread.interrupted())
method1();
}catch(InteruptedException e){
}
}
public static void main(){
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new Task());
exec.shutdownNow(); //线程被打断
/*或 Thread t = new Thread(new Task());
t.start();
t.interrupt(); */
}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值