首页 > 编程语言 >java多线程基础小白指南--关键字识别(start,run,sleep,wait,join,yield)

java多线程基础小白指南--关键字识别(start,run,sleep,wait,join,yield)

时间:2023-01-28 02:11:06浏览次数:50  
标签:java Thread start 线程 sleep 多线程 public wait

在学习java多线程基础上,会遇到几个关键字,理解并识别它们是掌握多线程的必备知识,下面,我将通过源码或者程序演示给出我对这几个关键字的理解,如果有不同意见,欢迎在评论区或者发私信与我探讨。

一、start和run

常见的面试八股中(其实本人没遇到过。。。。)涉及多线程start和run时,面试官会问哪个方法才是真正启动线程的真正方法?答案很明显,其实是start,可以通过以下这个实现可以检验

run方法其实就是个普通方法,start方法才是jdk中Thread类中定义启动线程的真正方法,start的语义可以理解为告诉jvm在合适的时机启动这个线程,这里的合适时机不一定是调用完start线程就开始工作,而是在调度器决定,观察start的源码

start方法主要可以分为三步,在调用start方法后,会先检查这个线程的状态是不是NEW(注意看红色的注解,关于线程状态我会再开一篇文章),然后加入线程组,最后调用一个native方法start0
所以如果线程两次调用start方法的话,会出发一个IllegalThreadStateException
run方法的源码更为简单,这个方法更重要的在线程启动的几种形式中发光发热

二、sleep,wait,join,yield方法

这几个关键字比较乱,我们从作用,锁,线程状态进行分析。

  • sleep方法查看源码可以知道这是个native方法,和cpp中sleep一样,它的作用是让线程进行休息,但是并不会释放掉锁(锁概念我会再开一篇文章讲述下synchronize关键字),线程sleep之后会处于TIME_WAITING状态,等待规定时间结束再运行,调用方式为Thread.sleep(时间)
  • wait方法注意在Object类中通用方法,设计在Object中的原因我的理解是”任何对象都可以作为一把锁”,这样直接设计成Object方法就好,这里建议去阅读wait方法的注释,我这里就不翻译了,注意wait方法必须使用在同步方法中,使用的格式为

    放在同步方法块中是为了避免死锁和永久等待,wait方法的作用是让当前获得锁的线程进行等待(这里等待唤醒条件可以是时间消耗完了或者被其他线程唤醒锁),在wait后会释放掉锁,,对应不同的唤醒条件wait后也有两种不同的状态,如果有time限制,那就是TIME_WAITING,如果没有设置time,就是WAITING
  • 验证sleep不会释放锁,wait会释放锁,同时sleep后状态是TIME_WAITING,wait状态是
点击查看代码
public class Wait {
    public  static Object object=new Object();

    static class Thread1 extends Thread{
        @Override
        public void run(){
            synchronized (object){
                System.out.println(Thread.currentThread().getName()+"开始执行了");
                try {
                    //Thread.sleep(600);
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程"+Thread.currentThread().getName()+"获得到了锁");
            }
        }
    }

    static class Thread2 extends Thread{
        @Override
        public void run(){
            synchronized (object){
                object.notify();
                System.out.println("线程"+Thread.currentThread().getName()+"调用了notify");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException{
        Thread1 thread1 = new Thread1();
        Thread2 thread2 = new Thread2();
        thread1.start();
        Thread.sleep(500);
        thread2.start();
    }

}
注意sleep和wait的输出结果的顺序加以分析
  • join方法的作用是让新线程加入当前线程,当前线程需要等待才能重新工作,比如如果主线程需要等待线程1工作完了才继续工作,那么就让线程1进行join即可,可以参考代码,注意注销join前后的输出变化
点击查看代码
public class Join {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "执行完毕");
            }
        });

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "执行完毕");
            }
        });

        thread1.start();
        thread2.start();
        System.out.println("开始等待子线程运行完毕");
        thread1.join();
        thread2.join();
        System.out.println("所有子线程已经执行完毕");
    }
}
join也有两种用法,当有time参数时,主线程(这里说的是演示代码中的情况)状态为TIME_WAITING,没有time参数则为WAITING状态,同时也不会释放掉锁
join状态
    public static void main(String[] args) throws InterruptedException {
        Thread mainThread=Thread.currentThread();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(mainThread.getState());
                    Thread.sleep(3000);
                    System.out.println("Thread-0 finished");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        thread.join(10000);
    }
  • yield方法用的比较少,是Thread的一个静态方法,它的作用是释放使用的cpu,不过它的状态依旧是RUNNABLE,同时也不会释放掉锁(好像没怎么用过,有没有大佬可以聊下使用场景)

标签:java,Thread,start,线程,sleep,多线程,public,wait
From: https://www.cnblogs.com/spark-cc/p/17067531.html

相关文章

  • java安全-RMI
    Java安全-RMI1、RMI原理浅析RMI(RemoteMethodInvocation)远程方法调用,是允许运行在一个JVM中的对象调用另一个JVM中的对象方法。两台虚拟机可以是同一台宿主机的不......
  • JavaScript学习笔记—正则表达式
    用来定义一个规则通过这个规则计算机可以检查一个字符串是否符合规则或者将字符串中符合规则的内容提取出来也是JS中的一个对象,所以要使用正则表达式,需要先创建正则表达......
  • java学习记录
    makrdown学习标题二级标题字体粗体斜体斜体加粗划线引用引用分割号图片可以用复制的东西超链接点击列表............
  • JavaScript基础知识
    1.编程语言  1.1编程      1.2计算机语言    1.3编程语言    1.4翻译器      1.5编程语言和标记语言的区别   ......
  • Java的基本数据类型
    Java的基本数据类型介绍Java中变量的概念、基本数据类型、基本数据类型变量的使用及它们之间转换,最后还会对基本数据类型与String的转换做一个说明。Author:MsuenbDat......
  • 运行解压版tomcat中的startup.bat一闪而退的解决办法
    Tomcat的startup.bat,它调用了catalina.bat,而catalina.bat则调用了setclasspath.bat,只要在setclasspath.bat的开头声明环境变量(红色两行)就可以了,原因是后来较新版本安装完不......
  • gRPC介绍(以Java为例)
    1.简介1.1gRPC的起源RPC是RemoteProcedureCall的简称,中文叫远程过程调用。用于解决分布式系统中服务之间的调用问题。通俗地讲,就是开发者能够像调用本地方法一样调用......
  • 用 JavaScript 制作一个新年的日历小工具
    2023年,让我们携手一道兔谋大业、做出兔出贡献!同打拼、共丰盈、多喜乐、长安宁,好运一路相随兔气扬眉!......
  • Java与Modbus通信
    1、引入依赖<dependency><groupId>com.intelligt.modbus</groupId><artifactId>jlibmodbus</artifactId><!--版本号可依照mave......
  • javafx程序运行
    下载openjfxhttps://gluonhq.com/products/javafx/openjfx的LTS版本好像要付费才能下载,所以勾选“Includeolderversions”下载一个非LTS的。下载后解压到一个地方执......