线程阻塞和中断
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(); */
}
}