并发 · 四 —— 线程状态 和 阻塞时中断的 interrupt()方法

线程有四种状态:新建、就绪、阻塞和死亡。

1)新建:当线程被创建时,它只会短暂地处于这种状态,在这段时间内,主要会执行一些初始化的的操作。

2)就绪:在这种状态下,只要调度器把时间片分配给线程,该线程就可以运行了。

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

4)死亡:处于该状态的线程将不再是可调度的,并且再也不会得到CPU时间,它的任务已结束了。任务死亡的通常方式是从run()方法返回。

注意:线程中的stop()方法已经被弃用了,主要是因为它不释放线程获取的锁,并且如果线程处于不一致的状态,其它任务可以在这种状态下浏览并修改它们,这样锁产生的问题就很难被发现了。

进入阻塞状态几种方式:

1)通过调用sleep(millisecond)使任务进入休眠状态,在这种情况下,任务在指定的时间内处于阻塞状态,不会获得CPU时间,并且不会释放线程自身所持有的锁(区别于调用wait()将线程挂起)。

2)调用wait()使线程挂起,直到线程得到了notify()或notifyAll()消息,线程重新才会进入就绪状态。

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

4)任务试图在某个对象上调用其同步控制方法,但是对象锁不同,此时就会被阻塞了。

**中断

常规手动停止线程的方法就是通过设置标志位的方法或者到达预先埋好的返回代码的位置,切记,stop()方法已经弃用了,由于不稳定,无法正常释放锁

public class text1 {
	
	volatile static boolean stop = false;
	
	public static void main(String[] args) {
		new Thread(new Runnable() {
			@Override
			public void run() {
				while (!stop) {
					System.out.println("运行中。。");
				}
			}
		}).start();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		stop = true;
	}
}

1、interrupt()

在Thread类提供interrupt()方法,用于中止正在被阻塞的任务。当打断一个正在被阻塞的任务时,通常还需要清理资源,这正如处理抛出异常,由于有这种需求存在,Java在设计阻塞时中断方法时,即在调用interrupt()设置线程为中断状态后,如果线程遇到阻塞就会抛出InterruptedException异常,并且将会重置线程的中断状态。例如

public class text2 {
	
	public static void main(String[] args) {
		new Thread(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				super.run();
				interrupt();// 将线程设置为中断状态
				
				System.out.println("遇到阻塞");				
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					System.out.println("阻塞被打断");
					// 在这里清理资源
					e.printStackTrace();
				}
				
				System.out.println("又遇到阻塞");				
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					System.out.println("阻塞被打断");
					// 在这里清理资源
					e.printStackTrace();
				}
				System.out.println("结束线程");
			}
		}.start();
	}
}

>> 运行的结果

遇到阻塞
阻塞被打断
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at text$1.run(text.java:19)
又遇到阻塞
结束线程

>>

从运行结果,我们可以看出,在调用interrupt()方法线程就被设置为中断状态,一旦遇到阻塞,就会立马中断阻塞,并抛出异常,并且重置中断状态位,当下次遇到阻塞就不会被中断并抛出异常。可以这么理解,调用interrupt(),便将线程的中断标志位置为true,当遇到阻塞(或者在调用interrupt方法中,正处于阻塞),都会立马中断阻塞,将线程的中断标志位置为false,并抛出异常。

public class text3 {
	public static void main(String[] args) {
		Thread t = new Thread(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				super.run();
				System.out.println("遇到阻塞");				
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					System.out.println("阻塞被打断");
					// 在这里清理资源
					e.printStackTrace();
				}
				System.out.println("阻塞结束");
				System.out.println("结束线程");
			}
		};
		t.start();
		try {
			Thread.sleep(500); // 为了确保线程已经运行
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("调用interrupt()");
		t.interrupt();
	}
}

>> 运行结果

遇到阻塞
调用interrupt()
阻塞被打断
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at text$1.run(text.java:17)
阻塞结束
结束线程

>>

正如上面的运行结果可以看出,如果线程正处于阻塞状态,调用interrupt()方法,会立马打断阻塞并抛出异常。

2、Thread.interrupted();

 除了遇到阻塞会抛出异常,并重置线程中断状态,Thread还有提供了一个interrupted()的静态方法,可以将当前的线程的中断状态重置。将上面第一个例子text1改进一下,它将不会阻塞被中断

public class text1_1 {
	
	public static void main(String[] args) {
		new Thread(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				super.run();
				interrupt(); // 将线程置为中断状态
				Thread.interrupted(); // 重置线程中断状态
				System.out.println("遇到阻塞");				
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					System.out.println("阻塞被打断");
					// 在这里清理资源
					e.printStackTrace();
				}
				System.out.println("阻塞结束");
				System.out.println("结束线程");
			}
		}.start();
		
	}

>> 运行结果

遇到阻塞
阻塞结束
结束线程

>>

3、isInterrupted()

可以通过调用这个方法打印当前线程的中断状态

public class text4 {
	public static void main(String[] args) {
		new Thread(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				super.run();
				interrupt(); // 设置中断状态
				System.out.println(interrupted()); // 打印中断状态
			}
		}.start();
		
	}
}

>>运行结果

true
>>

注意:当I/O和synchronized块上的等待是不可中断的的,也不需要InterruptException处理器。中断可以打断的有调用sleep()、调用wait()调起将线程挂起。

 

正文到这就完,哈哈哈,这篇主要是总结一些概念的东西,没有太难理解的地方,emmmm,写这篇还有个原因,是为得一下那个持之以恒的奖章,嘻嘻嘻嘻

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章