• 【多线程】Thread类的基本用法


    线程创建

    方法一:用一个类 继承Thread 重写run方法

    //创建一个类 继承Thread
    class MyThread extends Thread {
        //run方法是线程的入口
        @Override
        public void run() {
            while (true){
                System.out.println("hello Thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    这样一个线程就创建好了,然后可以创建MyThread实例。

    public class demo1 {
        public static void main(String[] args) throws InterruptedException {
            Thread thread = new MyThread();//向上转型 也可以写成MyThread myThread = new MyThread();
            //运行线程
            thread.start();
            while (true){
                System.out.println("hello main");
                //每1000毫秒打印一次 也就是休眠一秒
                Thread.sleep(1000);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    方法二:实现 Runnable 接口 重写run方法

    class MyRunnable implements Runnable {
        @Override
        public void run() {
            while (true){
                System.out.println("hello Runnable");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    我们可以通过实现Runnable接口来实现创建线程

    public class demo2 {
        public static void main(String[] args) throws InterruptedException {
            //runnable表示的是一个可运行的任务 这个任务是交给线程来负责执行的
            Runnable runnable = new MyRunnable();
            Thread t = new Thread(runnable);
            t.start();
            while (true){
                System.out.println("jello main");
                Thread.sleep(1000);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    方法三:使用匿名内部类,继承Thread 重写run方法

    public class demo3 {
        public static void main(String[] args) throws InterruptedException {
            //使用匿名类创建 Thread 子类对象
            Thread t = new Thread(){
                @Override
                public void run() {
                    while (true){
                        System.out.println("thread");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            };
            t.start();
            while (true){
                System.out.println("main");
                Thread.sleep(1000);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    方法四:使用匿名内部类,实现Runnable 重写run方法

    public class demo4 {
        public static void main(String[] args) {
            //使用匿名内部类创建 Runnable 子类对象
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true){
                        System.out.println("thread");
                    }
                }
            });
            t.start();
            while (true){
                System.out.println("main");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    方法五:使用 lambda 表达式创建 Runnable 子类对象

    public class demo5 {
        public static void main(String[] args) {
            //lambda 表达式创建 Runnable 子类对象  
            //lambda 表达式本质上是一个匿名函数
            Thread t = new Thread(()->{
               while (true){
                   System.out.println("thread");
               }
            });
            t.setDaemon(true);
            t.start();
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联。

    创建好线程之后我们可以运行程序观察线程,多线程运行的时候我们可以使用jdk的bin目录下的 jconsole.exe 来观察该进程里多线程的情况。如果运行 jconsole.exe 什么都不显示,就需要以管理员的方式运行。

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    Thread类的常见构造方法

    方法说明
    Thread()创建线程对象
    Thread(Runnable target)使用 Runnable 对象创建线程对象
    Thread(String name)创建线程对象,并命名
    Thread(Runnable target, String name)使用 Runnable 对象创建线程对象,并命名

    **Thread 的几个常见属性 **

    属性获取方法
    IDgetId()
    名称getName()
    状态getState()
    优先级getPriority()
    是否为后台线程isDaemon()
    是否存活isAlive()
    是否被中断isInterrupted()
    • ID 是线程的唯一标识,不同线程不会重复
    • 状态就是表示线程当前所处的一个情况
    • 优先级高的线程理论上来说更容易被调度到
    • 关于后台线程也可以叫守护线程,后台线程不结束也不会影响整个线程的结束,但是如果一个前台线程没有执行结束,那么整个进程也一定不会结束(JVM会在一个进程的所有非后台线程结束后,才会结束运行)
    • 是否存活,就是 run 方法是否运行结束

    线程中断

    在Java里面中断/销毁一个线程其实就是让run尽快执行结束,我们可以在代码中手动创建标志位来作为run的结束条件。

    public class demo6 {
        private static boolean isQuit = false;//设置标志位
        public static void main(String[] args) throws InterruptedException {
            Thread t = new Thread(()->{
                System.out.println("线程正在工作");
                while (!isQuit){
                    System.out.println("thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("线程工作结束");
            });
            t.start();
            Thread.sleep(5000);
            isQuit=true;
            System.out.println("hello");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    运行结果

    在这里插入图片描述

    上述方法手动创建标志位,当线程内部sleep的时候,,主线程修改变量,新线程不能及时响应,我们就可以使用Thread.currentThread().isInterrupted() 来代替自定义标志位。Thread 内部包含了一个 boolean 类型的变量作为线程是否被中断的标记 。

    方法说明
    public void interrupt()中断对象关联的线程,如果线程正在阻塞,则以异常方式通知, 否则设置标志位
    public static boolean interrupted()判断当前线程的中断标志位是否设置,调用后清除标志位
    public boolean isInterrupted()判断对象关联的线程的标志位是否设置,调用后不清除标志位
    public class demo7 {
        public static void main(String[] args) throws InterruptedException {
            Thread t = new Thread(()->{
                //Thread类内部 有一个标志位 可以用来判断当前的循环是否要结束
                //Thread.currentThread()就是获取当前线程
               while (!Thread.currentThread().isInterrupted()){
                   System.out.println("线程正在工作");
                   try {
                       Thread.sleep(1000);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                       //break; //加了break后会立即中断
                       //我们可以加一些其他的代码 然后再break 这样我们可以有更多的操作空间 
                   }
               }
            });
            t.start();
            Thread.sleep(5000);
            System.out.println("通过标志位使t线程终止");
            //interrupt可以使sleep内部出现一个异常 从而使线程被提前唤醒 手动创建出的标志位无法达到这个效果
            t.interrupt();//把上述标志位设置为true 即使线程内部出现阻塞 也可以被唤醒 
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    我们观察上面代码的运行结果

    在这里插入图片描述

    虽然异常出现了,sleep被唤醒但是循环没有终止,t 线程任然在继续工作,并没有停止。Java这样设定是因为,当java收到要中断信息的时候,我们希望它可以自由决定接下来怎么处理。

    线程等待

    等待一个线程我们使用 join()

    public class demo8 {
        public static void main(String[] args) throws InterruptedException {
            Thread t = new Thread(() -> {
                for (int i = 0; i < 5; i++) {
                    System.out.println("线程开始工作");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
            });
            t.start();
            System.out.println("线程开始等待");
            t.join();//主线程等待 t 线程结束 谁调用join谁是被等的
            System.out.println("等待结束");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    一旦调用 join 主线程就会发生阻塞,这样 t 线程就可以完成后面的工作,主线程要一直阻塞到 t 线程执行结束才会解除阻塞。

    方法说明
    public void join()等待线程结束
    public void join(long millis)等待线程结束,最多等 millis 毫秒
    public void join(long millis, int nanos)等待线程结束,但可以更高精度 最多等 nanos 纳秒

    线程休眠

    方法说明
    public static void sleep(long millis) throws InterruptedException休眠当前线程 millis 毫秒
    public static void sleep(long millis, int nanos) throws InterruptedException休眠当前线程 nanos 纳秒
    public class demo11 {
        public static void main(String[] args) throws InterruptedException {
            System.out.println(System.currentTimeMillis());
            Thread.sleep(3 * 1000);//休眠三秒
            System.out.println(System.currentTimeMillis());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 相关阅读:
    vcruntime140_1.dll是什么?关于计算机中缺失vcruntime140_1.dll的修复方法推荐
    300以内的开放耳机哪款好、300以内神级耳机推荐
    星域社区原版APP源码/社区交友App源码/动态圈子群聊php源码
    kafka 集群为什么依赖 zookeeper ?
    Python图像处理丨带你认识图像量化处理及局部马赛克特效
    【Transformers】第 6 章 :总结
    电子病历编辑器源码(Springboot+原生HTML)
    java技术专家面试指南80问【java学习+面试宝典】(六)
    js获取对象值得方式(在不确定对象参数的情况下获取值)
    STL常用容器——stack容器的使用
  • 原文地址:https://blog.csdn.net/qq_58032742/article/details/133807904