java 在阻塞时终结学习笔记

一个线程可以处于以下四种状态:
1:新建(new):当线程被创建时,它只会短暂地处于这种状态。此时它已经分配了必需的系统资源,并执行了初始化。此时刻线程已经有资格获得CPU时间了,之后调度器将把这个线程转变为可运行状态或阻塞状态。

2:就绪(Runnable):这种状态下,只要调度器把时间片分配给线程,线程就可以运行。也就是说,在任意时刻,线程可以运行也可以不运行。只要调度器能分配时间片给线程,它就可以运行,这不同于死亡和阻塞状态。

3:阻塞(Blocked):线程能够运行,但又某个条件阻止它运行。当线程处于阻塞状态时,调度器将忽略线程,不会分配给线程任何CPU时间,直到线程重新进入了就绪状态,它天才有可能执行操作。

4:死亡(Dead):处于死亡或终止状态的线程将不在时可调度的,并且在也不会得到CPU时间,它的任务已结束,或不再时可运行的,任务死亡的通常方式时从run()方法种返回,但是任务的线程还可以被中断,你将看到这一点。

进入阻塞状态,可能有以下原因:

1:sleep休眠。

2:通过调用wait()将线程挂起。直到线程得到了notify()或notifyAll()。

3:任务在等待某个输入/输出完成。

4:任务试图在某个对象上表用其他同步控制方法,但是对象锁不可用,因为另外一个任务已经获取了锁。

当你打断被阻塞的任务时,可能需要清理资源。正因为这点,在任务的run()方法中间打断,更像是抛出的异常,因此在java线程中的这种类型的异常中断中用到了异常。所以需要仔细编写try-catch子句以正确清理所有的事物。

Thread类包含Interrupt()方法,因此你可以中断被阻塞的任务,这个方法将设置线程的中断状态。如果一个线程已经阻塞或者试图执行阻塞操作,此时调用这个方法将抛出InterruptedException异常
当抛出该异常或者该任务调用Thread.interrupt方法时,中断状态将被复位。
Thread.interrupt()方法提供了离开run()而不抛出异常的第二种方式。为了调用Thread.interrupt()需要持有一个Thread对象。

新的current类库提供的Executor似乎在避免对Thread对象的直接操作。
若在Executor上调用shutdownNow(),那么它将发送一个interrupt()调用给它启动的所有线程
cancel(boolean)是一种中断由Executor启动的单个线程的方式。而此时,任务应该由submit()方法启动而不是execute()方法
submit()方法将返回一个范型Future<?>,在其上调用cancel(boolean)方法(参数为true)可以终止此任务

class SleepBlocked implements Runnable{
    
    
	public void run() {
    
    
		try {
    
    
			TimeUnit.MILLISECONDS.sleep(100);
		}catch(InterruptedException e) {
    
    
			System.out.println("InterruptedException");
		}
		System.out.println("Exiting SleepBlocked.run()");
	}
} 
class IOBlocked implements Runnable{
    
    
	private InputStream in;
    public IOBlocked(InputStream is) {
    
    in=is;}
	@Override
	public void run() {
    
    
		try {
    
    
			System.out.println("Waiting for read():");
			in.read();
		}catch(IOException e) {
    
    
			if(Thread.currentThread().isInterrupted()) {
    
    
				System.out.println("Interrupted from blocked I/O");
			}
			else {
    
    
				throw new RuntimeException(e);
			}
		}
		System.out.println("Exiting IOBlocked.run()");
	}
}
class SynchronizedBlocked implements Runnable{
    
    
	public synchronized void f() {
    
    
		while(true) {
    
    
			Thread.yield();
		}
	}
	public SynchronizedBlocked() {
    
    
		new Thread() {
    
    
			public void run() {
    
    
				f();
			}
		}.start();
	}
	public void run() {
    
    
		System.out.println("Trying to call f()");
		f();
		System.out.println("Exiting SynchronizedBlocked.run()");
	}
}
public class Interrupting {
    
    
	private static ExecutorService exec=Executors.newCachedThreadPool();
	static void test(Runnable r) throws InterruptedException{
    
    
		Future<?> f=exec.submit(r);
		TimeUnit.MILLISECONDS.sleep(100);
		System.out.println("Interrupting "+r.getClass().getName());
		f.cancel(true);
		System.out.println("Interrupting sent to "+r.getClass().getName());
	}
	public static void main(String[] args) throws InterruptedException {
    
    
		// TODO Auto-generated method stub
        test(new SleepBlocked());
        test(new IOBlocked(System.in));
        test(new SynchronizedBlocked());
        TimeUnit.MILLISECONDS.sleep(3);
        System.out.println("Absorbing with System.exit(0)");
        System.exit(0);
	}

}
/*
Exiting SleepBlocked.run()
Interrupting demo.SleepBlocked
Interrupting sent to demo.SleepBlocked
Waiting for read():
Interrupting demo.IOBlocked
Interrupting sent to demo.IOBlocked
Trying to call f()
Interrupting demo.synchronizedBlocked
Interrupting sent to demo.synchronizedBlocked
Absorbing with System.exit(0)
*/

以上程序的每个任务都表示了一种不同类型的阻塞。SleepBlock()是可中断的阻塞示例,而IOBlocked和SynchronizedBlocked是不可阻断的阻塞示例。所以I/O和在synchronized块上的等待是不可中断的,浏览代码可以发现无论是I/O还是尝试调用synchronized方法,都不需要任何InterruptedException处理器。
在SynchronizedBlocked中,我们必须首先获取锁,这是通过创建一个匿名的Thread类的一个实例来实现的,它调用了f()先获取了对象锁。因为f()方法内是一个死循环,永远不会返回,所以永远不会释放锁。此时Synchronized.run()方法在试图获取对象锁,并阻塞等待这个锁释放。
从以上程序示例看出:你不能中断正在试图获取synchronized锁或者试图执行I/O操作的线程。

对此的I/O处理方法

至于更加人性化中断I/O的nio类,等咱学完了再补上。

class BlockedMutex{
    
    
	private Lock lock=new ReentrantLock();
	public BlockedMutex() {
    
    
		lock.lock();
	}
	public void f() {
    
    
		try {
    
    
			lock.lockInterruptibly();
			System.out.println("lock acquired in f()");
		}catch(InterruptedException e) {
    
    
			System.out.println("Interruppted from lock acquisition in f()");
		}
	}
}
class Blocked2 implements Runnable{
    
    
	BlockedMutex blocked=new BlockedMutex();
	public void run() {
    
    
		System.out.println("Waiting for f() in BlockedMutex");
		blocked.f();
		System.out.println("Broken out of blocked call");
	}
}
public class Interrupting2 {
    
    

	public static void main(String[] args) throws InterruptedException {
    
    
		// TODO Auto-generated method stub
        Thread t=new Thread(new Blocked2());
        t.start();
        TimeUnit.MILLISECONDS.sleep(1);
        System.out.println("Issuing t.interrupt()");
        t.interrupt();
	}

}

以上程序:java SE5添加了一个特性,即在ReentrantLock上阻塞的任务具备可以被中断的能力,这与在synchronized方法或临界区阻塞的任务不同。

猜你喜欢

转载自blog.csdn.net/weixin_43916777/article/details/104316678