线程状态:
线程可以处于下面的四种状态之一:
新建(NEW)
线程被创建成功之后会短暂处于这个状态。线程已分配了必需的系统资源。并执行了初始化。此时线程已经有资格获得cpu时间片了。此后调度器将把这个线程转变为可运行或阻塞状态。
就绪(Rannable)在这种情况下,线程只要分配到时间片,他就运行。
阻塞(Blocked)线程能够运行,但是某种条件阻止了他的运行。当线程阻塞时候。调度器会忽略阻塞线程。不会分配时间片给它,直到线程重新进入可运行状态,才能继续执行操作。
死亡(Dead)处于死亡或者终止状态的线程,将不会被调度。他的任务已结束。或者不在是可运行的。任务线程死亡通常是从run 方法中返回。但是线程还是可以被中断的。
进入阻塞状态:
- sleep()
- await()
- 等待输出/输入完成
- 同步 等待锁
在较早的代码中可能使用 suspend() 和 resume() 来唤醒线程 (留坑、这个两个方法如何唤醒。为什么会导致死锁) ,但是现在已经被废止了(会导致死锁),stop() 也被废止了。因为它不释放线程获得的锁。
中断
下面将演示使用Executor展示interrupt()的用法:
public class SleepBlock implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
try {
TimeUnit.MILLISECONDS.sleep(600);
} catch (InterruptedException e) {
// e.printStackTrace();
System.out.println("SleepBlock Interrupted");
}
System.out.println("Exit SleepBlock run");
}
}
public class SynchronizedBlock implements Runnable {
public SynchronizedBlock() {
new Thread(this) {
@Override
public void run() {
// TODO Auto-generated method stub
f();
}
}.start();
}
public synchronized void f() {
while (true) {
Thread.yield();
}
}
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("try invoke fn");
f();
System.out.println("Exit synchronized run ");
}
}
public class IOBlock implements Runnable {
private InputStream in;
public IOBlock(InputStream in) {
super();
this.in = in;
}
@Override
public void run() {
// TODO Auto-generated method stub
// 暂无演示
}
}
public class InterruptTest {
private static ExecutorService exec = Executors.newCachedThreadPool();
static void test(Runnable target) {
Future<?> f = exec.submit(target);
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("interrupting " + target.getClass().getName());
f.cancel(true);
System.out.println("interrupt sent to " + target.getClass().getName());
}
public static void main(String[] args) throws Exception {
test(new SleepBlock());
test(new SynchronizedBlock());
TimeUnit.SECONDS.sleep(3);
System.out.println("system exit(0)");
System.exit(0);
}
}
运行结果:
上面总共表示了3种阻塞SleepBlock表示可中断阻塞,而IOBlock和SynchronizedBlaock表示不可中断阻塞。他们都是不可以被中断的。通过观察也可以知道 这两个不需要 InterruptException处理。
** 从输出可以看出,能够中断对sleep()的调用。(或者任何抛出InterruptException的操作) 但是你不能中断 IOBlock 和SynchronizedBlock 的操作。 这点有些令人烦恼特别是 执行IO程序的时候,这以为着他将锁住你的多线程程序的性能。特别是web程序。
public class CloseResourceTest {
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
ServerSocket server = new ServerSocket(9292, 1, InetAddress.getByName("127.0.0.1"));
Socket socket = new Socket("127.0.0.1", 9292);
InputStream in = socket.getInputStream();
exec.execute(new IOBlock(in));
exec.execute(new IOBlock(System.in));
TimeUnit.MILLISECONDS.sleep(100);
System.out.println("showdown all Thread");
exec.shutdownNow();
TimeUnit.SECONDS.sleep(1);
System.out.println("closing " + in.getClass().getName());
in.close();
TimeUnit.SECONDS.sleep(1);
System.out.println("closing:"+System.in.getClass().getName());
System.in.close();
}
}
public class IOBlock implements Runnable {
private InputStream in;
public IOBlock(InputStream in) {
super();
this.in = in;
}
@Override
public void run() {
// 暂无演示
try {
System.out.println("try to read");
in.read();
} catch (IOException e) {
if (Thread.currentThread().interrupted()) {
System.out.println("interupt IOBlock");
} else {
throw new RuntimeException();
}
}
System.out.println("Exit IOBlock run");
}
}
输出:
这个程序证明了 关闭底层资源之后 任务将解除阻塞。
nio 提供了更人性化的操作。被阻塞的nio通道会自动的响应中断。
(演示暂无 留坑)
一个锁多次由同一个任务获得:
public class MutiLock {
public synchronized void f1(int count) {
if (count-- > 0) {
System.out.println("f1:" + count);
f2(count);
}
}
public synchronized void f2(int count) {
if (count-- > 0) {
System.out.println("f2:" + count);
f1(count);
}
}
public static void main(String[] args) {
new Thread() {
@Override
public void run() {
new MutiLock().f1(10);
}
}.run();
}
}
JAVA SE5 并发库中新添加一个特性,即在ReentrantLock上阻塞的任务具有中断的能力:
这与synchronized的阻塞完全不同。
public class BlockedMutex {
private Lock lock = new ReentrantLock();
public BlockedMutex() {
lock.lock();
}
public void f(){
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
System.out.println("lock intrupt");
}
}
}
public class Blocked2 implements Runnable {
BlockedMutex block = new BlockedMutex();
@Override
public void run() {
System.out.println("try lockinterruptly");
block.f();
System.out.println("exiting Blocked2 run");
}
public static void main(String[] args) throws Exception {
Thread t = new Thread(new Blocked2());
t.start();
TimeUnit.SECONDS.sleep(1);
System.out.println("to interrupt");
t.interrupt();
}
}
从运行结果可以看出这个被打断了。
中断检查
public class NeedClean {
private final int id;
public NeedClean(int id) {
this.id = id;
System.out.println(this);
}
@Override
public String toString() {
return "NeedClean [id=" + id + "]";
}
public void clean() {
System.out.println("clean :" + this);
}
}
public class Blocked3 implements Runnable {
public static void main(String[] args) throws Exception {
Thread t = new Thread(new Blocked3());
t.start();
TimeUnit.MILLISECONDS.sleep(110);
System.out.println("send interrupt sign");
t.interrupt();
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
// point1
NeedClean need1 = new NeedClean(1);
try {
System.out.println("sleep");
TimeUnit.MILLISECONDS.sleep(100);
// blocking operation
// point 2
NeedClean need2 = new NeedClean(2);
try {
System.out.println("counting");
for (long i = 0; i < 2500000000l; i++) {
@SuppressWarnings("unused")
double d = (Math.E + Math.PI) / i + Math.E + Math.PI % 0.3 + 16591;
}
System.out.println("finish counting");
} finally {
need2.clean();
}
} finally {
need1.clean();
}
}
} catch (InterruptedException e) {
System.out.println("exit .....");
}
// TODO Auto-generated method stub
}
}
中断发生在 Sleep:
中断发生在 counting:
解释一下输入
- 如果中断发生在 point 2 之后就是阻塞操作sleep 之后 非阻塞的运算之中时候 会执行完 for循环 然后执行finally 从 顶部的额while跳出循环
- 如果中断发生在 point1 和point2 之间(在sleep之前或者sleep之中)的话,那么任务在执行第一次阻塞操作之前 经由InterruptedException退出。
介绍此类的 只要目的是为了说明 在涉及相应 interrupt 的类和程序时候 一定要做好 清理策略关于形成 interrupt interrupted isinterrupted 的区别:
1、interrupt
interrupt方法用于中断线程。调用该方法的线程的状态为将被置为"中断"状态。
注意:线程中断仅仅是置线程的中断状态位,不会停止线程。需要用户自己去监视线程的状态为并做处理。支持线程中断的方法(也就是线程中断后会抛出interruptedException的方法)就是在监视线程的中断状态,一旦线程的中断状态被置为“中断状态”,就会抛出中断异常。
2、interrupted 和 isInterrupted
首先看一下该方法的实现:
public static boolean interrupted () {
return currentThread().isInterrupted(true);
}
该方法就是直接调用当前线程的isInterrupted(true)方法。
然后再来看一下 isInterrupted的实现:
public boolean isInterrupted () {
return isInterrupted( false);
}
这两个方法有两个主要区别:
interrupted 是作用于当前线程,isInterrupted 是作用于调用该方法的线程对象所对应的线程。(线程对象对应的线程不一定是当前运行的线程。例如我们可以在A线程中去调用B线程对象的isInterrupted方法。)
这两个方法最终都会调用同一个方法,只不过参数一个是true,一个是false;
第二个区别主要体现在调用的方法的参数上,让我们来看一看这个参数是什么含义
先来看一看被调用的方法 isInterrupted(boolean arg)的定义:
private native boolean isInterrupted( boolean ClearInterrupted);
原来这是一个本地方法,看不到源码。不过没关系,通过参数名我们就能知道,这个参数代表是否要清除状态位。
如果这个参数为true,说明返回线程的状态位后,要清掉原来的状态位(恢复成原来情况)。这个参数为false,就是直接返回线程的状态位。
这两个方法很好区分,只有当前线程才能清除自己的中断位(对应interrupted()方法)
总结的来说 就是 isinterrupted 每次只会查询标志位 不会改变标志位的状态
而 interrupted 测试线程是否中断 线程的中断状态 由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回 false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。
public class Interrupt {
public static void main(String[] args) throws Exception {
Thread t = new Thread(new Worker());
t.start();
Thread.sleep(20);
t.interrupt();
System.out.println("Main thread stopped.");
}
public static class Worker implements Runnable {
public void run() {
System.out.println("Worker started.");
try {
for (long i = 0; i < 2500000000l; i++) {
@SuppressWarnings("unused")
double d = (Math.E + Math.PI) / i + Math.E + Math.PI % 0.3 + 16591;
}
} finally {
System.out.println(Thread.interrupted()); // 如果为true的话 会重置标志位 为false 如果为false的话那就不会重置
System.out.println(Thread.interrupted());
System.out.println(Thread.interrupted());
}
System.out.println("Worker stopped.");
}
}
}
**强调一点 抛出InterruptedException 时候jvm 会丢失当前线程的的中断标志,所以在catch 块中的 interrupted或者isInterrupted 都返回false **