博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
多线程学习(十二)
阅读量:4682 次
发布时间:2019-06-09

本文共 9792 字,大约阅读时间需要 32 分钟。

线程状态:

线程可以处于下面的四种状态之一:

新建(NEW)

线程被创建成功之后会短暂处于这个状态。线程已分配了必需的系统资源。并执行了初始化。此时线程已经有资格获得cpu时间片了。此后调度器将把这个线程转变为可运行或阻塞状态。

就绪(Rannable)

在这种情况下,线程只要分配到时间片,他就运行。

阻塞(Blocked)

线程能够运行,但是某种条件阻止了他的运行。当线程阻塞时候。调度器会忽略阻塞线程。不会分配时间片给它,直到线程重新进入可运行状态,才能继续执行操作。

死亡(Dead)

处于死亡或者终止状态的线程,将不会被调度。他的任务已结束。或者不在是可运行的。任务线程死亡通常是从run 方法中返回。但是线程还是可以被中断的。

进入阻塞状态:

  1. sleep()
  2. await()
  3. 等待输出/输入完成
  4. 同步 等待锁

在较早的代码中可能使用 suspend() 和 resume() 来唤醒线程 (留坑、这个两个方法如何唤醒。为什么会导致死锁) ,但是现在已经被废止了(会导致死锁),stop() 也被废止了。因为它不释放线程获得的锁。

中断

1114580-20170511202410379-256371019.png

下面将演示使用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); }}

运行结果:

1114580-20170511205644972-1620973954.png
上面总共表示了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");    }}

输出:

1114580-20170511214059066-256144973.png
这个程序证明了 关闭底层资源之后 任务将解除阻塞。
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();    }}

1114580-20170511222257347-521320716.png

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();    }}

1114580-20170511224901004-1166558925.png

从运行结果可以看出这个被打断了。

中断检查

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:

1114580-20170512134754097-819962789.png

中断发生在 counting:

1114580-20170512140240597-1106637246.png

解释一下输入

  1. 如果中断发生在 point 2 之后就是阻塞操作sleep 之后 非阻塞的运算之中时候 会执行完 for循环 然后执行finally 从 顶部的额while跳出循环
  2. 如果中断发生在 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

转载于:https://www.cnblogs.com/joeCqupt/p/6833176.html

你可能感兴趣的文章
Mysql扩展之replication概述
查看>>
C++中数值的后缀
查看>>
EventModify
查看>>
C中int8_t、int16_t、int32_t、int64_t、uint8_t、size_t、ssize_t区别
查看>>
python day2 模块初识、pyc定义
查看>>
一道算法作业题(续)
查看>>
Machine Learning From Scratch-从头开始机器学习
查看>>
基础数据结构
查看>>
python url库学习
查看>>
找“水王”
查看>>
018-伸展树
查看>>
FPM打包工具
查看>>
JDK版本不兼容问题之:一台机器安装多个版本的JDK
查看>>
20145302张薇《Java程序设计》第八周学习总结
查看>>
Log4net的配置-按照日期+文件大小混合分割
查看>>
const char*、char*、char* const、char[]、string的区别
查看>>
SQL学习笔记:基础SQL语句
查看>>
python管理网络设备的一些模块
查看>>
VirtualProtect、VirtualLock、VirtualUnlock
查看>>
Stl
查看>>