多线程——线程的常用方法

sleep

sleep是一个静态方法,只有两个重载方法,其中一个传入毫秒数, 另一个既需要毫秒数也需要纳秒数。

public static native void sleep(long millis) throws InterruptedException;
public static void sleep(long millis, int nanos) throws InterruptedException

sleep方法会使当前线程进入指定毫秒的休眠,暂停执行,虽然给定了休眠的时间,但是最终要以系统的定时器和调度器的精度为准,
sleep的休眠有一个很重要的特性,就是不会放弃monitor锁的所有权

JDK 1.5以后,引入了一个枚举TimeUnit 其对sleep方法进行了很好的封装

    public void sleep(long timeout) throws InterruptedException {
        if (timeout > 0) {
            long ms = toMillis(timeout);
            int ns = excessNanos(timeout, ms);
            Thread.sleep(ms, ns);
        }
    }

使用实例

      TimeUnit.SECONDS.sleep(10);
      TimeUnit.MILLISECONDS.sleep(200);
      TimeUnit.HOURS.sleep(1);

yield

yield方法属于一种启发式的方法,其会提醒调度器我愿意放弃当前的CPU资源,如果CPU资源不紧张,则会忽略这个提醒。即yield只是一个提示,CPU调度器并不会担保每次都能满足yield的提示。

yield VS sleep

  1. 是否导致线程上下文的切换
    sleep会导致当前线程暂停指定的时间,没有CPU的时间片消耗

yield只会CPU调度器发一个提示,如果CPU调度器不紧张则会忽略这个提示,如果没有忽略这个提示,会导致线程上下文的切换

  1. 导致的线程状态切换
    sleep 会导致线程短暂进入Block, 会在给定的时间内释放CPU资源
    yield 会是Running状态的线程进入Runnable的状态(如果CPU调度器没有忽略这个提示的话)

  2. 时间上
    sleep 几乎百分百完成给定时间的休眠
    yield 的提示并不能一定担保

  3. 中断信号
    一个线程sleep 另一个线程调用interrupt 会捕获到中断信号
    yield则不会

priority

线程的优先级,理论上优先级比较高的线程会获得优先被CPU调度的机会。但是事实上并不会如你所愿,设置线程的优先级也是一个hint知操作:

  • 对于root用户,它会hint操作系统你想要的设置的优先级别,否则它会被忽略
  • 如果CPU太忙,设置优先级可能会获得更多CPU时间片,但是闲时优先级的高低几乎不会有任何作用。
    所以,不要在程序设计中企图用线程的优先级来绑定某些特性业务,或者让业务严重依赖线程的优先级。

线程的默认优先级

    /**
     * The minimum priority that a thread can have.
     */
    public static final int MIN_PRIORITY = 1;

   /**
     * The default priority that is assigned to a thread.
     */
    public static final int NORM_PRIORITY = 5;

    /**
     * The maximum priority that a thread can have.
     */
    public static final int MAX_PRIORITY = 10;

    public final void setPriority(int newPriority) {
        ThreadGroup g;
        checkAccess();
        if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
            throw new IllegalArgumentException();
        }
        if((g = getThreadGroup()) != null) {
            if (newPriority > g.getMaxPriority()) {
                newPriority = g.getMaxPriority();
            }
            setPriority0(priority = newPriority);
        }
    }

上面源码分析得出,线程的优先级不能大于10 和小于1 , 如果指定线程的优先级大于线程所在组的最大优先级,则指定优先级将会失效,取而代之的是当前线程所在组的最大线程优先级。如果小于所在组的最大线程优先级, 则设置为需要设置的线程优先级。

线程的上下文类加载器

线程的上下文类加载器,就是这个线程是有那个类加载器加载的,如果在没有修改线程上下文类加载器的情况下,则保持与父线程同样的类加载器
如果设置该线程的类加载器,这个方法则可以打破Java类加载器的父委托机制,有时也称为Java类加载器的后门。

interrupt

public void interrupt();
/**
此方法是一个静态方法,虽然也用于对当前线程是否被中断,但是和成员方法isInterrupted方法的区别,
就是调用该方法会直接擦除掉线程的interrupt标识,

注意:如果当前线程被打断了,那么第一次调用interrupted方法会返回true, 
并且立即擦除interrupt标识,  第二次包括以后调用永远都会返回false, 
除非再次期间线程又一次被打断
*/
public static boolean interrupted();
/**
Thread的成员方法,主要是判断当前线程是否被中断,该方法
仅仅是对interrupt标识的一个判断,并不会影响标识发生任何改变
*/
public boolean isInterrupted();

调用如下方法会使当前线程进入阻塞状态

  1. Object 的wait()
  2. Object 的wait(long)
  3. Object 的wait(long, int)
  4. Thread 的sleep(long)
  5. Thread 的sleep(long, int)
  6. Thread 的join()
  7. Thread 的join(long)
  8. Thread 的join(long, int)
  9. InterruptibleChannel的IO操作
  10. Selector的wakeup方法
  11. 其他

而调用当前线程的Interrupt方法,则就可以打断阻塞, 因此此方法也称为可中断方法。
注意:
打断一个线程不等于该线程的生命周期结束,仅仅是打断了当前线程的阻塞状态。
如果一个线程执行可中断方法被阻塞时,调用interrupt方法将其中断,会导致其中断标识被清除。
如果一个线程已经试死亡状态,那么尝试对其调用interrupt方法会直接被忽略

join

与sleep一样, 它也是一个可中断方法。也即如果有其他线程执行了对当前线程的interrupt操作,它也会捕捉到中断信号,并且擦除线程的interrupt标识。
join某个线程A , 会使当前线程B(比如main线程)进入等待,知道线程A结束生命周期,或者到达指定的时间,那么在此期间线程B是Blocked的

实例:
比如需要你做一个接口请求,这个请求的返回需要调用多个接口的返回进行组合,这里用join来做并行多个请求,等都返回后再进行组合,当然也可用JDK自带的CountDownLatch 或者CyclicBarrier等,这里我们用join来实现一把。

public class ClientRequestTask extends Thread {

    public static void main(String[] args) {
        List<ClientRequestTask> tasks = IntStream.range(1, 3).boxed()
                .map(url -> new ClientRequestTask("url:" + url)).collect(Collectors.toList());

        tasks.forEach(Thread::start);

        tasks.forEach(task -> {
            try {
                task.join();
            } catch (InterruptedException e) {

            }
        });

        List<String> list = new ArrayList<>();
        tasks.stream().map(ClientRequestTask::getResults).forEach(list::addAll);
        System.out.println(list);
    }

    private String url;

    private final List<String> results = new ArrayList<>();

    public ClientRequestTask(String url) {
        this.url = url;
    }


    public List<String> getResults() {
        return results;
    }

    @Override
    public void run() {
        try {
            System.out.println(url + " start request data");
            int i = ThreadLocalRandom.current().nextInt(10);
            TimeUnit.SECONDS.sleep(ThreadLocalRandom.current().nextInt(10));
            results.add(url + "---------" + i);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

如何关闭一个线程

  1. JDK有一个Deprecated的方法stop, 但是该方法关闭线程时不会释放掉monitor锁,所以官方已经不推荐使用此方法了。
  2. 线程结束生命周期
  3. 捕获中断信号关闭线程
  4. 使用volatile开关控制
  5. 异常退出
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,183评论 6 516
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,850评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,766评论 0 361
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,854评论 1 299
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,871评论 6 398
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,457评论 1 311
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,999评论 3 422
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,914评论 0 277
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,465评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,543评论 3 342
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,675评论 1 353
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,354评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,029评论 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,514评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,616评论 1 274
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,091评论 3 378
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,685评论 2 360

推荐阅读更多精彩内容