Thread 类的基本用法

Thread 类的基本用法

Thread类的概念

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

1.1Thread的常见构造方法

方法说明
Thread()创建线程对象
Thread(Runnable target)使用Runnable对象创建线程对象
Thread(Runnable target,String name)使用Runnable对象创建线程对象,并命名
Thread(ThreadGroup group,Runnable target)线程可以被用来分组管理,分好的组即为线程组
Thread t1 = new Thread();
Thread t2 = new Thread(new MyRunnable());
Thread t3 = new Thread("名字");
Thread t4 = new Thread(new MyRunnable()"名字");
1.2Thread 的几个常见属性
属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()
对于上面几个属性解释

1.ID是线程的唯一的标识,不同的线程不会重复
2.名称是各种调试工具用到
3.状态表示线程当前所处的一个情况
4.优先级高的线程理论上来说更容易被调度到,但实际上并没有什么区别
5.后台线程(守护线程),不会阻止进程结束,后台工作没有做完,进程依旧可以结束,但前台线程会阻止进程结束,前台工作没有做完,进程不能够结束
6.代码里手动创建的线程,默认都是前台的,包括main默认也是前台的,其他jvm自带的线程都是后台的,但是可以通过手动使用setDaemon()设置为后台线程

       Thread t = new Thread(new Runnable() {
           @Override
           public void run() {
               while (true){
                   System.out.println("1");
               }
           }
       },"t");
       t.setDaemon(true);
       t.start();

把t设置为守护线程/后台线程
此时进程的结束与否就和t无关了

7.JVM会在一个进程的所有非后台进程结束后,才会结束运行
8.是否存活,即run()方法是否结束。

Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println("hello");
                }
            }
        }, "t1");
        t1.start();
        
        while (true) {
            try {
                Thread.sleep(1000);
                System.out.println(t1.isAlive());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

如果t1的run还没跑,isAlive就为false;
如果t1的run正在跑,isAlive就为true;
如果t1的run跑完了,isAlive就为false;

在这里插入图片描述
9.线程中断,中断的意思并不是让线程立刻停止,而是通知线程应该要终止,是否真的终止,取决于具体代码。比如,我妈叫我拖地,我正在打游戏,而我现在有三个选择,第一个是马上去;第二个是等打完游戏,再去;第三个是直接摆烂,这里的中断也类似这个意思,根据具体代码进行选择,线程中断的两种方法,在下面进行说明。

1.3启动一个线程-start()

通过run方法创建一个线程对象,但是线程对象被创建出来,并不代表着线程就开始运行,这里就要区别run()和start()的区别:run()方法是描述线程要做的工作;start()方法会让内核创建一个PCB,此时PCB代表一个真正的线程,并让新线程调用run
即调用start()方法,才真的在操作系统底部创建出一个线程

1.4中断一个线程

目前常见中断线程的两种方法:
1.通过共享的标记来进行沟通
2.调用interrupt()方法来通知

1.使用标志位来控制线程是否要停止

Thread t = new Thread(() -> {
            while (true) {
                System.out.println("hello");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();

        Thread.sleep(3000);
        //在主线程里面可以随时通过flag的变量的取值,来操作t线程是否结束
        flag = false;
        

2.使用Thread自带的标志位,来进行判定

A

                                
Thread t = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("hello");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        Thread.sleep(3000);
        t.interrupt();


Thread.currentThread().这个是Thread类的静态方法,通过这个方法可以获取当前线程,类似this;
isInterrupted()是在t.run中被调用,这里就是获取t的线程,这里要注意的是true表示被终止,false表示未被终止,所以要在前面取反,才能继续走

A的代码的结果如下:

在这里插入图片描述

为什么会出现这个现象的原因是:当代码执行到t.interrupt(),internet会做两件事情:
1.把线程内部标志位,设置为true
2.如果线程在进行sleep,就会触发异常,把sleep唤醒,但是把sleep唤醒,会导致刚才设置的标志位变为false(即清空了标志位)

所以简单而言,线程t忽略你的请求

如果把代码修改成如下:增加一个break
B

Thread t = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("hello");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }
            }
        });
        t.start();
        Thread.sleep(3000);
        t.interrupt();

B的代码的结果如下:

在这里插入图片描述

因为break,此时线程t立刻响应你的终止请求

如果把代码修改成如下:增加一个延时
C

Thread t = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("hello");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                    break;
                }
            }
        });
        t.start();
        Thread.sleep(3000);
        t.interrupt();

C的代码的结果如下:
虽然运行结果与B一致,但是延迟执行中断

在这里插入图片描述

线程t稍后进行终止

1.5等待一个线程

线程是一个随机调度过程,等待线程,就是控制两个线程的结束顺序

下面是示例代码

    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                System.out.println("HELLO");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        t.start();
        System.out.println("join之前");
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("join之后");
    }

代码的结果是

在这里插入图片描述

这个代码的实质就是,通过此处的join让当前的main线程来等待t线程执行结束
原本是在执行t.start()之后,t线程和main线程就会并发执行,抢占式执行,main和t都是继续执行下去,但是有了join之后,join会阻塞main线程的执行,一直阻塞到t线程执行结束,main线程才会从join中恢复过来,在继续执行main线程。

在这里插入图片描述

假设开始执行join的时候t已经结束,结果又会变成如何?

    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                System.out.println("HELLO");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("join之前");
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("join之后");
    }

在join之前添加sleep(5000),使开始执行join的时候t已经结束,结果如下

在这里插入图片描述

此时执行join的时候,t已经结束,那么join不会阻塞,会立即执行。

1.6获取当前线程引用
方法说明
public static Thread currentThread();返回当前线程对象的引用
    public static void main(String[] args) {
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName());
    }
1.7休眠当前线程
方法说明
public static void sleep(long millis) throws InterruptedException休眠当前线程 millis毫秒
public static void sleep(long millis, int nanos) throwsInterruptedException可以更高精度的休眠
    public static void main(String[] args) throws InterruptedException {
        System.out.println(System.currentTimeMillis());
        Thread.sleep(3 * 1000);
        System.out.println(System.currentTimeMillis());
    }
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值