Thread 的类的基本用法

1.线程创建

线程的创建有许多方法,这里我们主要讲三种。

1.继承Thread类

class MyThread extends Thread {
    @override
    public void run{
        System.out,println("线程运行时执行的代码");
    }
}
MyThread t = new MyThread();//创建一个实例
t.start();//调用start方法,启动线程

2.实现Runnable接口

class MyRunnable implements Runnable {
    @override
    public void run {
        System.out.println("线程执行时执行的代码");
    }
}
Thread t = new Thread(new Runnable);//将Runnabled对象作为Thread构造方法的参数
t.start();//调用start方法,启动线程,

3.lambda表达式

Thread t = new Thread(() -> {
    System.out.println("线程运行时执行的代码");
});//lambda本质上是一个匿名函数,主要用来实现“回调函数”效果,这里不多做拓展。

2.线程中断

在Java中,要销毁或者是终止一个线程就需要想办法让run方法尽快执行完毕。我们可以在代码中手动创建一个标志位,来作为run的执行结束的条件。事实上,很多线程执行得很久,是因为陷入了循环,所以我们跳出循环就好了。我们来看如下代码:

public class Main {
    private static  boolean isQuit = false;
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            while (!isQuit) {
                System.out.println("线程工作中");//此处语句可执行其他任意任务
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("线程工作完毕");
        });
        t.start();
        Thread.sleep(5000);
        isQuit = true;//若没有此语句,循环就会一直执行下去
        System.out.println("设置isQuit为true");
    }
}
​

上述方案是一个可行的方案,但是不够完美。

1.需要我们手动创建一个变量

2.当线程内部在sleep时,主线程修改变量,新线程内部不能及时响应

事实上,线程中断还有其他方法,见如下代码:

class Main{
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            //Thread类中有现成的标志位,来判断当前的循环是否要结束
            while (!Thread.currentThread().isInterrupted()) {
                //Thread.currentThread()-->获取当前线程的实例(Thread),实际上结果就是经常用的t
                //isInterrupted(),Thread内部的一个标志位,可以用来判断线程是否要结束
                System.out.println("线程工作中");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                    break;//此处加break的原因见下文
                }
            }
        });
        t.start();
        Thread.sleep(5000);
        System.out.println("让t线程终止");
        t.interrupt();//此语句就是把上述标志位设置为true
    }
}
​

此外,利用此种方法,即使线程内部的逻辑出现阻塞,也是可以用这个方法唤醒的。

Thread.sleep(1000);正常来说,sleep会休眠到时间到才会结束,而此处的interrupt则可以在sleep内部触发一个异常,从而被提前唤醒。这个时候又会出现一个问题,sleep因被提前触发异常而唤醒后,t线程并没有结束。事实上,sleep抛出异常后,会清除之前设置的标志位。为什么这样设定呢?Java是期望当前线程收到“要中断”的信号时,它能够自由决定接下来怎么处理。怎么处理呢?我们可以加一个break。(不妨再回头看看代码?)

3.线程等待

什么是线程等待?简单来说,就是让一个线程等待另一个线程执行结束再继续执行。本质上就是为了控制线程结束的顺序。我们可以利用join实现线程等待效果。

注意:主线程中,调用t.join,此时就是主线等待 t线程 先结束。

我们看如下代码:

class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            for(int i = 0; i < 5; i++) {
                System.out.println("t线程执行中");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t.start();
        //让主线程等待t线程执行结束,一旦调用join,主线程就会进入阻塞状态。=直到t线程执行结束
        t.join();
        System.out.println("主线程执行");
    }
}

值得注意的是,调用join时如果相应的线程已经结束了,那么主线程就不会进入阻塞状态。

现在我们再来假设一个场景,倘若t线程陷入了一个死循环,难道主线程要一直等待下去吗?答案自然是否定的。join还有一个带参数的构造方法,可以设置等待的时间。

4.线程休眠

线程休眠一般用sleep方法,前面已经使用过很多次了,此处就不再赘述。不过一个值得注意的点是,利用sleep方法休眠线程1000毫秒,并不一定就是正正好好的1000毫秒,由于还存在调度的开销,可能会多那么个几毫秒。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值