常见方法

1、线程休眠(Sleep)。

public static void main(String[] args) throws InterruptedException {
        //线程开始时先打印当前时间
        System.out.println(LocalDateTime.now());
        for (int i = 0; i < 5; i++) {
            //休眠5秒钟,然后打印当前时间
            Thread.sleep(5000);
            System.out.println(LocalDateTime.now());
        }
    }

输出结果:

2022-12-21T00:04:17.494
2022-12-21T00:04:22.503
2022-12-21T00:04:27.518
2022-12-21T00:04:32.523
2022-12-21T00:04:37.531
2022-12-21T00:04:42.540

2、线程让步(Yield)。

//继承Thread类,并重写run方法
public class TextThread extends Thread {

    public TextThread() {
        super();
    }

    public TextThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            //打印当前线程ID、名称、状态。
            System.out.println("子线程ID:" + this.getId()
                    + ",子线程名称:" + this.getName()
                    + ",子线程状态" + this.getState()
                    + ",子线程执行次数:" + i);
            Thread.yield();
        }
    }
}
public static void main(String[] args) throws InterruptedException {
        TextThread textThread = new TextThread();
        TextThread textThread1 = new TextThread();
        textThread.start();
        textThread1.start();

    }

输出结果:

子线程ID:12,子线程名称:Thread-0,子线程状态RUNNABLE,子线程执行次数:0
子线程ID:13,子线程名称:Thread-1,子线程状态RUNNABLE,子线程执行次数:0
子线程ID:12,子线程名称:Thread-0,子线程状态RUNNABLE,子线程执行次数:1
子线程ID:12,子线程名称:Thread-0,子线程状态RUNNABLE,子线程执行次数:2
子线程ID:13,子线程名称:Thread-1,子线程状态RUNNABLE,子线程执行次数:1
子线程ID:12,子线程名称:Thread-0,子线程状态RUNNABLE,子线程执行次数:3
子线程ID:13,子线程名称:Thread-1,子线程状态RUNNABLE,子线程执行次数:2
子线程ID:12,子线程名称:Thread-0,子线程状态RUNNABLE,子线程执行次数:4
子线程ID:13,子线程名称:Thread-1,子线程状态RUNNABLE,子线程执行次数:3
子线程ID:12,子线程名称:Thread-0,子线程状态RUNNABLE,子线程执行次数:5
...

从结果上可以看出,Thread-0执行打印结束后,会去执行Thread-2的打印。但是我们发挥发现其中还是会有连续执行的情况:

子线程ID:12,子线程名称:Thread-0,子线程状态RUNNABLE,子线程执行次数:1
子线程ID:12,子线程名称:Thread-0,子线程状态RUNNABLE,子线程执行次数:2

这是因为yield()方法中止了当前线程,使它进入到就绪状态,继续等待CPU调度,也就是主动放弃了CPU的调度权。但是当前线程依旧会继续参与到CPU调度竞争中,所以说当前线程中止后,也是会继续获取到CPU的调度权,来继续执行打印的。

3、线程加入(join)

public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("线程名称:" + Thread.currentThread().getName() + ",执行次数:" + i);
            }
        });
        thread.start();
        thread.join();

        for (int i = 0; i < 5; i++) {
            System.out.println("线程名称:" + Thread.currentThread().getName() + ",执行次数:" + i);
        }
    }

输出结果:

线程名称:Thread-0,执行次数:0
线程名称:Thread-0,执行次数:1
线程名称:Thread-0,执行次数:2
线程名称:Thread-0,执行次数:3
线程名称:Thread-0,执行次数:4
线程名称:main,执行次数:0
线程名称:main,执行次数:1
线程名称:main,执行次数:2
线程名称:main,执行次数:3
线程名称:main,执行次数:4

使用join之后,主线程会进入阻塞状态,直至当前线程执行结束,才会执行其他线程。

 

4、线程优先级。

thread.setPriority(1);

线程优先级为1-10,默认为5。线程优先级越高,线程获取CPU调度的机会越多。

 

5、守护线程。

线程分为两大类:用户线程(前台线程)和守护线程(后台线程)。

守护线程是一种在后台运行的特殊线程。他可以独立运行,可以自动结束自己的生命周期。而非守护线程不具备这样的特性。

垃圾回收器线程属于守护线程。

 代码演示:

public class DaemonThread extends Thread {
    @Override
    public void run() {while (true) {
            System.out.println("线程名称:" + Thread.currentThread().getName());
        }
    }
}



public static void main(String[] args) {
        DaemonThread thread = new DaemonThread();
        thread.setDaemon(false);//默认不使用守护线程
        thread.start();

        System.out.println("the application is stopped");
    }

输出结果:

...
线程名称:Thread-0 线程名称:Thread-0 线程名称:Thread-0 线程名称:Thread-0 线程名称:Thread-0 线程名称:Thread-0 线程名称:Thread-0 线程名称:Thread-0 线程名称:Thread-0 线程名称:Thread-0
...

此时因为该线程内存在存在死循环,导致JVM无法正常关闭。

开启守护线程:

 thread.setDaemon(true);//开启守护线程

输出结果:

...
线程名称:Thread-0
线程名称:Thread-0
线程名称:Thread-0
线程名称:Thread-0
线程名称:Thread-0
线程名称:Thread-0
线程名称:Thread-0
Process finished with exit code 0

总结:

默认情况下我们创建的线程或线程池都是用户线程,守护线程是为用户线程服务的。当一个程序中的所有用户线程都执行完成之后程序就会结束运行。
程序结束运行时不会管守护线程是否正在运行,由此我们可以看出守护线程在 Java 体系中权重是比较低的。

 

posted @ 2022-12-21 00:44  Amireux-126  阅读(19)  评论(0)    收藏  举报