常见方法
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 体系中权重是比较低的。

浙公网安备 33010602011771号