线程常用操作

来源:互联网 发布:linux中使用getch 编辑:程序博客网 时间:2024/06/16 16:52

本文讲解了Java中中断线程的概念和常用方法以及让步操作和优先级等概念,对线程的常用操作进行初步了解。

1 停止线程

Java停止一个线程是通过调用Thread类的interrupt()方法来实现的,下面具体讲一下它的相关用法。

1.1 interrupt() != 立即终止

调用interrupt()并不会像break语句那样直接就终止线程,它仅仅是在当前线程中打了一个停止的标记,并不是真的停止线程。
国际惯例,上栗子:

自定义线程类

package com.trigl.concurrent.simplethread;/** * 用于讲解interrupt()方法的线程类 * @author 白鑫 * @date 2016年3月31日 上午11:39:04 */public class InterruptThread extends Thread {    @Override    public void run() {        super.run();        for (int i = 0; i < 500000; i++) {            System.out.println("i=" + (i + 1));        }    }}

测试方法

    /**     * 先让线程启动,线程会打印50万条数据,会花费一定时间。     * 所以让test方法休眠1秒,再停止线程。     * @throws InterruptedException     */    @Test    public void testInterruptThread() throws InterruptedException {        InterruptThread thread = new InterruptThread();        thread.start();        Thread.sleep(1000);        thread.interrupt();        System.out.println("end");    }

输出结果

这里写图片描述

从结果看并没有打印到i=500000,貌似是interrupt()方法起作用了,其实非也,关键在:

Thread.sleep(1000);

这条代码上,它将当前test方法的线程休眠了1秒钟,在这一秒中之内线程thread打印到了图中所示的最后一条i=123878,然后test方法执行完毕了就结束了,而thread线程还在后台执行,只不过由于test方法结束了,所以不再打印到控制台上。如果我们将休眠时间改为10秒,即改为:

Thread.sleep(10000);

再来看一下结果:

这里写图片描述

可以看到,50万条数据全部打印了出来,所以interrupt()方法并没有起作用。那么问题来了,到底怎么才能真的停止线程呢?

1.2 判断线程是否是停止状态

在介绍如何停止线程之前,首先看一下如何判断线程的停止状态。Thread类提供了两种方法:

  • public static boolean interrupted() // 测试当前线程是否已经中断
  • public boolean isInterrupted() // 测试线程是否已经中断

1.2.1 interrupted()

interrupted()是一个静态方法,通过

Thread.interrupted();

来直接直接调用,它判断的是当前正在执行的线程的中断状态,上栗子:

测试方法

    /**     * 测试Thread的interrupted()方法     */    @Test    public void testInterrupted() {        Thread.currentThread().interrupt();        System.out.println("Thread.interrupted()" + Thread.interrupted());        System.out.println("Thread.interrupted()" + Thread.interrupted());        System.out.println("end");    }

输出结果

Thread.interrupted()=trueThread.interrupted()=falseend

结果很奇怪,明明是两条相同的代码,为什么结果一个是true一个是false呢?
从官方API中找答案:

boolean java.lang.Thread.interrupted()
Tests whether the current thread has been interrupted. The interrupted status of the thread is cleared by this method. In other words, if this method were to be called twice in succession, the second call would return false (unless the current thread were interrupted again, after the first call had cleared its interrupted status and before the second call had examined it).
A thread interruption ignored because a thread was not alive at the time of the interrupt will be reflected by this method returning false.

说的很明白:如果连续两次调用该方法,则第二次调用将返回false(除非正好在第二次调用前当前线程又中断了一次);如果线程已经不再存活(not alive),那么将忽略中断状态标记,调用该方法会返回false。

1.2.2 isInterrupted()

该方法判断的是一个Thread对象的中断状态,而不是当前线程的中断状态。上栗子来比较与interrupted()方法的不同:

测试方法

    /**     * 测试Thread的isInterrupted()方法     * @throws InterruptedException      */    @Test    public void testIsInterrupted() throws InterruptedException {        InterruptThread thread = new InterruptThread();        thread.start();        thread.interrupt();        System.out.println("thread.isInterrupted()=" + thread.isInterrupted());        System.out.println("thread.isInterrupted()=" + thread.isInterrupted());        System.out.println("end");    }

输出结果

thread.isInterrupted()=truei=1thread.isInterrupted()=trueendi=2i=3......

从结果中可以看到,方法isInterrupted()并未清除状态标志,所以打印了两个true。

1.3 使用异常法停止线程

具体实现就是在一个自定义线程类的run方法中,首先判断一下线程是否是停止状态,如果是停止状态,则手动抛出一个InterruptedException异常来中断线程,实例如下:

自定义线程类

package com.trigl.concurrent.simplethread;/** * 使用异常法停止线程 * @author 白鑫 * @date 2016年3月31日 上午11:39:04 */public class InterruptThread extends Thread {    @Override    public void run() {        super.run();        try {            for (int i = 0; i < 500000; i++) {                if (Thread.interrupted()) {                    System.out.println("已经是停止状态了!我要退出了!");                    throw new InterruptedException();                }                System.out.println("i=" + (i + 1));            }            System.out.println("如果你能看到我说明线程并没有真的被中断!");        } catch (Exception e) {            // TODO: handle exception            System.out.println("进入到InterruptThread类run方法中的catch了!");            e.printStackTrace();        }    }}

测试方法

    @Test    public void testInterruptThread() throws InterruptedException {        InterruptThread thread = new InterruptThread();        thread.start();        Thread.sleep(1000);        thread.interrupt();        System.out.println("end");    }

输出结果

......i=121981i=121982i=121983end已经是停止状态了!我要退出了!进入到InterruptThread类run方法中的catch了!java.lang.InterruptedException    at com.trigl.concurrent.simplethread.InterruptThread.run(InterruptThread.java:16)

1.4 在沉睡中停止线程

分为两种,另一种是先休眠后停止线程,一种是先停止线程后休眠,这两种都会抛出java.lang.InterruptedException的错误

1.4.1 先休眠后停止

自定义线程类

package com.trigl.concurrent.simplethread;/** * 先休眠后停止线程 * @author 白鑫 * @date 2016年4月1日 上午10:33:11 */public class InterruptedWhenSleep extends Thread {    @Override    public void run() {        super.run();        try {            System.out.println("run begin");            Thread.sleep(20000);            System.out.println("run end");        } catch (InterruptedException e) {            // TODO: handle exception            System.out.println("在沉睡中被停止!进入catch!isInterrupted()=" + this.isInterrupted());            e.printStackTrace();        }    }}

测试方法

    @Test    public void testInterruptedWhenSleep() throws InterruptedException {        InterruptedWhenSleep thread = new InterruptedWhenSleep();        thread.start();        Thread.sleep(200); // 休眠在中断前面,保证thread先休眠再中断        thread.interrupt();    }

输出结果

run begin在沉睡中被停止!进入catch!isInterrupted()=falsejava.lang.InterruptedException: sleep interrupted    at java.lang.Thread.sleep(Native Method)    at com.trigl.concurrent.simplethread.InterruptedWhenSleep.run(InterruptedWhenSleep.java:14)

1.4.2 先停止后休眠

自定义线程类

package com.trigl.concurrent.simplethread;/** * 先停止后休眠线程 * @author 白鑫 * @date 2016年4月1日 上午10:38:08 */public class InterruptedWhenSleep1 extends Thread {    @Override    public void run() {        super.run();        try {            for (int i = 0; i < 100000; i++) {                System.out.println("i=" + (i + 1));            }            System.out.println("run begin");            Thread.sleep(20000);            System.out.println("run end");        } catch (InterruptedException e) {            System.out.println("先停止,再遇到了sleep!进入catch!");            e.printStackTrace();        }    }}

测试方法

    @Test    public void testInterruptedWhenSleep1() throws InterruptedException {        InterruptedWhenSleep1 thread = new InterruptedWhenSleep1();        thread.start();        thread.interrupt();        Thread.sleep(1000); // 加这个休眠是为了延迟test方法的完成,从而thread的打印报错信息        System.out.println("end");    }

输出结果

......i=99999i=100000run begin先停止,再遇到了sleep!进入catch!java.lang.InterruptedException: sleep interrupted    at java.lang.Thread.sleep(Native Method)    at com.trigl.concurrent.simplethread.InterruptedWhenSleep1.run(InterruptedWhenSleep1.java:17)end

1.5 暴力停止线程

可以使用Thread类的stop()方法暴力停止线程,但是这个方法是不安全的,而且是已被弃用作废的(deprecated),最好不要使用。这个例子看看就可以了,反正没人会用这个方法233333。

自定义线程类

package com.trigl.concurrent.simplethread;/** * 用stop()方法暴力停止线程 * @author 白鑫 * @date 2016年4月1日 上午10:50:51 */public class StopThread extends Thread {    private int i = 0;    @Override    public void run() {        try {            while (true) {                i++;                System.out.println("i=" + i);                Thread.sleep(1000);            }        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }}

测试方法

    @SuppressWarnings("deprecation")    @Test    public void testStopThread() throws InterruptedException {        StopThread thread = new StopThread();        thread.start();        Thread.sleep(5000);        thread.stop();    }

输出结果

i=1i=2i=3i=4i=5

1.6 使用return停止线程

将方法interrupt()和return结合使用也可以停止线程。

自定义线程类

package com.trigl.concurrent.simplethread;/** * 使用return停止线程 * @author 白鑫 * @date 2016年4月1日 下午3:21:16 */public class UseReturnInterrupt extends Thread {    @Override    public void run() {        while (true) {            if (this.isInterrupted()) {                System.out.println("停止了!");                return;            }            System.out.println("timer=" + System.currentTimeMillis());        }    }}

测试方法

    @Test    public void testUseReturnInterrupt() throws InterruptedException {        UseReturnInterrupt thread = new UseReturnInterrupt();        thread.start();        Thread.sleep(1000);        thread.interrupt();        System.out.println("end");    }

输出结果

......timer=1459495136740timer=1459495136740timer=1459495136740停止了!end

2 线程的让步操作

线程使用yield()方法来放弃当前的CPU资源,将它让给其他任务去占用CPU执行时间。但放弃的时间不确定,有可能刚刚放弃,马上又获得CPU时间片。
上栗子~

自定义线程类

package com.trigl.concurrent.simplethread;/** * 线程放弃CPU资源 * @author 白鑫 * @date 2016年4月1日 下午3:54:18 */public class YieldThread extends Thread {    @Override    public void run() {        long beginTime = System.currentTimeMillis();        int count = 0;        for (int i = 0; i < 50000000; i++) {            count = count + (i + 1);//          Thread.yield(); // 主动放弃CPU资源,将这行代码注释和不注释分别跑一下,看一下区别        }        long endTime = System.currentTimeMillis();        System.out.println("用时:" + (endTime - beginTime) + "毫秒!");    }}

测试方法

    @Test    public void testYieldThread() throws InterruptedException {        YieldThread thread = new YieldThread();        thread.start();        Thread.sleep(10000);    }

不调用yield()方法输出结果

用时:1毫秒!

调用yield()方法输出结果

用时:4255毫秒!

可以看到,处理5千万自加1操作,调用yield()和不调用yield()方法差别还是很大的,相差了近4000倍。

3 线程的优先级

在操作系统中,线程可以划分优先级,优先级高的线程得到的CPU资源多,也就是CPU优先执行优先级较高的线程对象中的任务。
设置优先级使用setPriority()方法,得到优先级使用getPriority()方法。
在Java中,线程的优先级分为1~10这10个等级,如果小于1或者大于10,则JDK抛出IllegalArgumentException异常。
JDK中使用3个常量来预置定义优先级的值,代码如下:

  • public final static int MIN_PRIORITY = 1;
  • public final static int NORM_PRIORITY = 5;
  • public final static int MAX_PRIORITY = 10;

在Java中,线程的优先级具有继承性,比如A相称启动了B线程,则B线程的优先级与A是一样的。
上栗子:

自定义线程类

package com.trigl.concurrent.simplethread;/** * 线程的优先级的继承特性 * @author 白鑫 * @date 2016年4月1日 下午4:48:28 */public class InheritPriorityThread extends Thread {    @Override    public void run() {        System.out.println("InheritPriorityThread run priority=" + this.getPriority());    }}

测试方法

    @Test    public void testInheritPriorityThread() {        System.out.println("test thread begin priority=" + Thread.currentThread().getPriority());//      Thread.currentThread().setPriority(6); // 设置当前线程的优先级        System.out.println("test thread end priority=" + Thread.currentThread().getPriority());        InheritPriorityThread thread = new InheritPriorityThread();        thread.start();    }

输出结果

test thread begin priority=5test thread end priority=5InheritPriorityThread run priority=5

将代码:

//      Thread.currentThread().setPriority(6); // 设置当前线程的优先级

前的注释去掉,再次运行,得到结果如下:

test thread begin priority=5test thread end priority=6InheritPriorityThread run priority=6

可以看到,由于在test方法中启动了另一个线程,所以他们的线程优先级相同,都是6.

OVER

1 0
原创粉丝点击