首页 > 其他分享 >多线程sleep、yield、wait、join方法的使用和区别

多线程sleep、yield、wait、join方法的使用和区别

时间:2024-01-27 10:23:34浏览次数:25  
标签:join yield 线程 sleep 多线程 方法 wait

使用和介绍

sleep方法

sleep方法的官方注释(翻译后):

    /**
     * 根据系统计时器和调度程序的精度和准确性,使当前执行的线程休眠(暂时停止执行)指定的毫秒数。线程不会失去任何监视器的所有权(不释放锁)。
     *
     * @param millis 以毫秒为单位的睡眠时间长度
     * @throws IllegalArgumentException 如果参数{millis}的值为负数
     * @throws InterruptedException     如果有线程中断了当前线程。当抛出此异常时,当前线程的中断状态将被清除。
     */
    public static native void sleep(long millis) throws InterruptedException;

sleep方法是Thread类的静态方法,而且是‘native’方法所以一般情况下是看不到具体实现代码的,不过通过注释也可以简单了解它的使用方法:使当前执行的线程休眠(暂时停止执行)指定的毫秒数。

所谓多线程实际上是CPU的快速切换调用!sleep()方法既然让当前线程休眠了,所以必然要释放CPU处于阻塞状态,然后等sleep的时间结束后再次变为可运行状态等待CPU的调用。

yield方法

 yield方法的官方注释(翻译后):

    /**
     * 向调度程序提示当前线程愿意放弃其对处理器的当前使用。调度程序可以忽略此提示。
     * <p>
     * Yield是一种启发式尝试,旨在改善线程之间的相对进度,否则线程将过度使用CPU。它的使用应该与详细的分析和基准测试相结合,以确保它确实具有预期的效果。
     * <p>
     * 使用这种方法很少是合适的。它可能有助于调试或测试目的,有助于重现由于竞争条件而产生的错误。在设计并发控制结构(如{java.util.concurrent.locks}包中的结构)时,它也可能很有用。
     */
    public static native void yield();

yield方法也是Thread类的静态方法,也是‘native’方法。根据注释分析得出三点:

1、‘放弃其对处理器的当前使用’意思是该方法可以让当前线程让出CPU资源;

2、‘调度程序可以忽略此提示’说明线程并没有被阻塞,而是可以随时被调用,也就是处于可运行状态;

3、既然yield()方法可以让出CPU而且也可能被忽视即让出后立即获取资源则说明只有具有相同优先级或者更高优先级的线程才可以与yield()让出的线程竞争CPU的调度,也就是涉及到线程的优先级。

wait方法

  wait方法的官方注释(翻译后):

/**
     * 让当前线程处于等待状态,直到另一个线程调用{notify}或者{notifyAll}方法。
     * 换句话来说,这个方法和 wait(0)是一样的。
     * <p>
     * 当前线程必须拥有此对象的监视器(锁).线程释放这个监视器(锁)的拥有权,并且直到另一个线程通过调用{notify}或者{notifyAll}方法通知在该对象的监视器上等待唤醒的线程
     * 然后线程处于等待状态,直到它能够重新获得监视器的所有权并恢复执行。
     */
    public final void wait() throws InterruptedException {
        wait(0);
    }

    public final native void wait(long timeout) throws InterruptedException;

wait()方法是Object类的方法,而且wait()方法实际上是调用wait(long timeout)方法,而wait(long timeout)方法也是native方法。根据注释可知:wait方法首先要和锁一起使用,而且wait会使当前线程释放CPU处于阻塞状态的同时,也会释放锁,然后等另一个线程通过notify()或者notifyAll()方法来唤醒它,并且在被唤醒之后才处于可运行状态。

notify方法:

    /**
     * 唤醒在该对象的监视器上等待的单个线程。如果有任何线程正在等待此对象,则会选择其中一个线程进行唤醒。
     * 这种选择是任意的,由执行人员自行决定。线程通过调用其中一个{wait}方法来等待对象的监视器。
     */
    public final native void notify();

notifyAll方法:

    /**
     * 唤醒在该对象的监视器上等待的所有线程。线程通过调用其中一个{wait}方法来等待对象的监视器。
     */
    public final native void notifyAll();

join方法

 join方法的官方注释(翻译后):

/**
     * 一直等到调用线程执行完毕(死掉).
     *
     * @throws InterruptedException 如果有线程中断了当前线程。当抛出此异常时,当前线程的<i>中断状态</i>将被清除。
     */
    public final void join() throws InterruptedException {
        join(0);
    }

    public final synchronized void join(long millis)
            throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            //当线程还在运行状态时调用wait方法
            while (isAlive()) {
                wait(0);
            }
        } else {
            //当线程还在运行状态时调用wait方法
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

join方法是Thread类中的一个方法,该方法的定义是阻塞当前正在运行的线程A,开始执行调用此方法的线程B直到线程B执行完毕。

问题1:现有T1、T2、T3三个线程,如何保证这三个线程能按T1、T2、T3的顺序执行?

答案:将T1线程join到T2线程的run方法中,将T2线程join到T3线程的run方法中。

public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("t1");

            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    t1.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t2");
            }
        });
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    t2.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t3");
            }
        });
        t1.start();
        t2.start();
        t3.start();
    }

问题2:join方法是如何阻塞当前线程的?

答案:join方法实际上是用了synchronized锁,并调用wait方法。并且在JVM源码中封装了notifyAll方法从而在调用线程执行结束后唤醒当前线程。参考:https://blog.csdn.net/u010983881/article/details/80257703

区别

 sleep()和wait()

相同点:

都可以让当前线程让出CPU资源而且是处于阻塞状态。

不同点:

1、sleep()是Thread类的方法,wait()是Object类的方法;

2、sleep()需要指定参数,wait()不需要参数;

3、sleep()到时间后自动处于可运行状态,wait()方法需要另一个线程通过notify()或者notifyAll()方法将其唤醒;

4、sleep()方法的调用线程不需要拥有锁资源,wait()方法的线程在有锁资源的情况下调用。

sleep()和yield()

相同点:

1、都可以让当前线程让出CPU资源;

2、都是Thread类的静态方法;

不同点:

1、sleep()需要指定参数。yield()方法不需要参数;

2、sleep()在指定时间内线程处于阻塞状态等时间结束后才处于可运行状态,yield()让出资源的线程直接处于可运行状态;

3、sleep()处于可运行状态时不涉及线程优先级,和其他线程公平竞争资源,而yield()是为了让同级别或者更高优先级的线程先获取资源。

wait()和yield()

相同点:

1、都可以让当前线程让出CPU资源;

2、都可以不指定参数;

不同点:

1、yield()是Thread类的方法,wait()是Object类的方法;

2、yield()让出资源后自动处于可运行状态,wait()方法需要另一个线程通过notify()或者notifyAll()方法将其唤醒;

3、yield()方法的调用线程不需要拥有锁资源,wait()方法的线程在有锁资源的情况下调用。

标签:join,yield,线程,sleep,多线程,方法,wait
From: https://www.cnblogs.com/Bernard94/p/17989601

相关文章

  • Python 多线程的局限性及适用场景解析
     Python是一门功能强大且广泛应用的编程语言,然而在使用多线程方面,它存在一些局限性。本文将探讨Python多线程的局限性,并分析其适用场景,帮助读者更好地理解Python多线程的实际运用。 正文: 一、Python的全局解释器锁(GIL) Python的全局解释器锁(GlobalInterpreterLock,简称GIL)是P......
  • 【解答】面试题:如何快速解决跨库join表关联?
    面试题:如何快速解决跨库join表关联?有一天产品经理提了一个需求,要关联查询A库的xxx表和B库的xxx表(跨库join),做实时分析(查询的表不固定,后期业务还会调整)。Java研发更改代码实现比较困难,大数据团队反馈可以,但不能保证实时性,会有30分钟左右的数据延迟。产品经理说我这个需求很急,30分......
  • [SQLAlchemy] sqlAlchemy学习笔记(3): 在orm中使用join
    JOIN连接表➡️官方文档⬅️在sqlalchemy中实现JOIN/ON语句,需要用到Select.join()或者Select.join_from()假设我们有两张表(在python中就变成了两个类)User和Address,User表中有一列addresses,表示该用户使用的所有地址的集合(反映到代码中,就是Address对象的集合);同时Ad......
  • .net 高并发(二,多线程)
    一,多线程可以通过System.Threading.Thread类来实现。下面是一个简单的示例,展示如何使用Thread类创建和管理多个线程: usingSystem; usingSystem.Threading;   classProgram { staticvoidMain() { //创建两个线程 Thre......
  • OpenMP学习 第十章 超越通用核心的多线程
    第十章超越通用核心的多线程基于通用核心的附加子句并行构造的附加子句:num_threads(integer-expression)用于设置线程总数.if(scalar-expression)用于为并行构造提供条件分支.copyin(list)proc_bind(master|close|spread)为了测试num_threads子句与if子句的用法,......
  • iOS 多线程复习
    iOS中的线程主要有四种:1.pThread2.NSThread3.GCD4.NSOpreaction基础知识:线程、任务和队列的概念: 异步、同步&并行、串行的特点:组合特点:  1.pThread C语言所写,面向过程,使用较少.oc:#pragmaMark-pThread-(void)pThreadDemo{pthread_tpthre......
  • GDB调试之多线程死锁调试(二十四)
    调试代码如下所示:#include<thread>#include<iostream>#include<vector>#include<mutex>usingnamespacestd;mutex_mutex1;mutex_mutex2;intdata1;intdata2;intdo_work_1(){ std::cout<<"线程函数do_work_1开始"<<......
  • rust使用lazy_static对全局变量多线程并发读写示例
    首先需要在项目依赖Cargo.toml添加lazy_static依赖项[dependencies]lazy_static="1.4.0"示例代码如下:uselazy_static::lazy_static;usestd::sync::{RwLock,RwLockReadGuard,RwLockWriteGuard};usestd::thread;#[derive(Debug)]structSharedData{data:Vec<......
  • jmeter读取csv文件控制多线程不重复读取
    在Jmeter中设置并发为S,循环次数为N时,参数化文件可能被重复读取N次,无法保证每次读取的数据均不一样,此处介绍保证数据不重复的方法。在线程组下添加一个CSVDataSetConfig,具体配置如下图:将配置中默认:RecycleonEOF=True,StopthreadonEOF=False修改为:RecycleonEO......
  • Java 多线程交替打印
    目录题目方案一:synchronized方法二:ReentrantLock方法三:ReentrantLock+Condition(非公平锁)方法四:ReentrantLock+Condition(公平锁)方法五:Semaphore题目使用三个线程T1、T2、T3,如何让他们按顺序交替打印10次ABC。方案一:synchronizedpublicclassSynchronizedLockPrint......