线程常用操作

本文讲解了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()=true
Thread.interrupted()=false
end

结果很奇怪,明明是两条相同的代码,为什么结果一个是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()=true
i=1
thread.isInterrupted()=true
end
i=2
i=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=121981
i=121982
i=121983
end
已经是停止状态了!我要退出了!
进入到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()=false
java.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=99999
i=100000
run 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=1
i=2
i=3
i=4
i=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=1459495136740
timer=1459495136740
timer=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=5
test thread end priority=5
InheritPriorityThread run priority=5

将代码:

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

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

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

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

OVER

Java线程中的常用命令包括: 1. 创建线程: - 继承Thread类,重写run()方法,然后创建线程对象并调用start()方法。 - 实现Runnable接口,重写run()方法,然后创建线程对象并将其作为参数传递给Thread类的构造方法,然后调用start()方法。 2. 启动线程: - 调用线程对象的start()方法来启动线程。 3. 线程休眠: - 使用Thread类的sleep()方法来使线程休眠一段时间。 4. 线程等待: - 使用Object类的wait()方法让线程等待,直到其他线程调用notify()或notifyAll()方法唤醒它。 5. 线程唤醒: - 使用Object类的notify()方法或notifyAll()方法来唤醒等待的线程。 6. 加入线程: - 使用Thread类的join()方法,让一个线程等待另一个线程执行完毕。 7. 线程优先级: - 使用Thread类的setPriority()方法设置线程的优先级,优先级范围为1到10,默认为5。 8. 线程同步: - 使用synchronized关键字或Lock对象来同步多个线程对共享资源的访问。 9. 线程中断: - 使用Thread类的interrupt()方法来中断线程的执行。 10. 线程状态控制: - 使用Thread类的getState()方法来获取线程的状态,使用Thread类的yield()方法让出当前线程的CPU执行时间片。 11. 线程池: - 使用Executor框架中的线程池来管理和调度线程的执行。 12. 线程间通信: - 使用wait()、notify()、notifyAll()方法以及synchronized关键字等实现线程间的通信。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值