Thread 类的基本用法

一、线程创建的5种基本用法 

       1.定义一个类来继承Thread类

        首先创建一个类来继承Thread,然后重写Thread类中的run方法。

        然后在main函数里创建MyThread类的实例,然后通过start方法来创建和启动线程

        2.实现Runnable接口 
        首先创建一个类来实现Runnable接口,然后重写run方法

        然后在main函数中创建Thread类的实例, 调用Thread的构造方法时将Runnable对象作为参数传递,然后通过start方法来创建和启动线程

        3. 通过匿名内部类创建Thread子类对象
        在main函数中创建Thread类的实例,然后创建匿名内部类重写run方法,通过start方法来创建和启动线程

        4.通过匿名内部类创建 Runnable子类对象
         在main函数创建Thread实例,调用Thread的构造方法时将Runnable对象作为参数传递,使用匿名类创建Runnable子类对象,然后通过start方法来创建和启动线程

        5.通过lambda表达式创建Runnable子类对象 
         在main函数创建Thread实例,调用Thread的构造方法时将Runnable对象作为参数传递,使用lambda表达式创建Runnable子类对象,然后通过start方法来创建和启动线程

 二、 线程的休眠

        通过调用sleep方法来休眠当前线程

        在上述代码中,在t1线程中的循环里,通过调用Thread类的静态方法sleep使得循环每循环一次都会休息1s,sleep '()' 里的单位是ms(1s = 1000ms),sleep函数需要try/catch来处理异常

 、线程的等待

        在操作系统中,多线程的执行是随机调度,抢占式执行的过程,所以我们无法确定哪个线程先被调度,哪个线程先执行完,通过线程等待就是来确定线程结束的顺序。线程等待顾名思义就是一个线程等待另一个线程,通过join方法来实现线程的等待。例如现在有两个线程t1和t2,在t2线程中通过t1.join()就是为了让t2等待t1,这样如果t2先线程执行完了就不会结束线程,而是会等待t1线程结束后,t2线程才结束。具体代码如下:

运行结果:

        从上述代码可以看出,t1线程中的for循环运行5次休息5秒,而t2线程的for循环运行2次,休息2买秒 ,t1和t2线程并发执行后按理来说应该是t2线程先结束,但由于在t2线程中有t1.join(),这使得t2线程执行完后会等待t1线程结束后才结束,所以才有了运行结果中的t1线程先结束然后t2线程才结束的结果。
        在join方法的中存在有带参数的join方法,在上述代码中的t1.join()如果改成t1.join(2000)(单位为ms),就说明t2线程只会等待t1线程2s,如果t1线程2s后没有执行结束,那t2线程就执行结束,不再等待t1线程。

四、获取线程实例

        在Java中通过currentThread()方法来获取线程实例,该方法为Thread的静态方法,具体用法如下:

运行结果:

        通过currentThread()方法可以获得当前线程的引用,通过上述代码可以看出,使用currentThread()方法获取到了主线程main的引用。

五、线程中断

        在Java中一个结束一个线程是比较温柔的过程,要是一个线程t2想让一个线程t1中断,不是强制让t1线程结束执行,这样就会导致t1线程的程序执行了一半,此时t1线程执行代码的结果数据就是半成品,这样的数据没有任何用处,我们希望的是要不就执行结束,要不就不执行。所以如果t2线程想让t1线程提前结束,就需要让t1线程的run方法更快执行结束。目前常见的两种方式:

        1.通过共享的标记来进⾏沟通

代码运行结果:

        在上述代码中使用了共享的标记isTrue,当线程t1执行时,由于isTrue 为true,在t1线程中的run方法一直在循环,当2s后t2线程执行到isTrue = false,把共享标志改了导致t1线程中的run方法循环结束,导致run方法也结束了,使得t1线程结束,这就是通过共享标志让t2线程结束t1线程。

        2.调用interrupt()方法

        在上述代码中,由于在lambda表达式中不知道引用t所以需要curreThread()方法来获取当前线程引用,然后调用Thread的成员isInterrupted这个成员是boolean类型,初始值为false),然后在main线程中通过调用interrupt()方法来设置标志位,把isInterrupt改成true,则线程t的的循环就结束了,就使得t线程的run方法结束,这就是通过Interrupt()方法来让线程提前结束。
        运行结果:

        从上述图片来看,运行结果与我们分析的不一样,通过interrupt(),没有使t线程结束执行,而且还抛出一个异常,这是因为在t线程的run方法里,主要的时间都在执行sleep(1000),所以当用t.interrupt()来设置标志位的时候,线程t大概率在执行sleep(1000),而interrupt()方法会唤醒sleep,这使得sleep在休眠的时候被唤醒,从而抛出异常。而且sleep被唤醒后又会清空刚才设置的标志位刚刚把isInterrupt设为的true又清空为false),导致线程没有结束继续执行。要想真正的结束继承需要在sleep的catch里加上break或return。

        运行结果 :

  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Milliliter___

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值