Thread中有一些常见的方法,对于我们学习多线程来说,这些方法都需要了解,包括像sleep,join,yield等,学好了这些方法以及原理,在后续的学习中肯定会事半功倍。对于像interrupt这类方法,线程中断的方法,会在下一期文章中详细介绍,线程中断涉及的方法比较多,也容易混淆,但是很重要,所以这里我们就简单提一下这个方法就好。
1. sleep()
sleep作为最常见的方法之一,其作用就是使调用sleep的所在线程进入睡眠状态。它会让调用该方法的所在线程主动放弃CPU资源,进入阻塞状态,如果指定了睡眠时间,到达了指定时间之后线程就会进入就绪状态,等待调度器的调用。sleep()方法是Thread类的静态方法,如果调用线程对象.sleep()方法并不是该线程就休眠,而是哪一个线程里面执行了sleep()方法哪一个线程就休眠。
2. join()
执行该方法的线程进入阻塞状态,直到调用该方法的线程结束后再由阻塞转为就绪状态。
使用场景:主线程中开启了一个几个子线程进行数据计算,但是主线程最后会需要其中某一个线程的计算结果,这时候就需要主线程调用子线程的join方法,等待子线程完成数据计算任务,然后再进行后续的操作。
代码语言:javascript复制 public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(()->{
try {
TimeUnit.SECONDS.sleep(2);
System.out.println("子线程1执行完了");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread thread2 = new Thread(()->{
try {
TimeUnit.SECONDS.sleep(5);
System.out.println("子线程2执行完了");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread2.start();
thread1.start();
try {
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程执行完了");
}
子线程2睡眠5秒,子线程1睡眠2秒,正常情况下应该是主线程最先完成,然后才是子线程1,子线程2执行完成,但是在代码中调用了thread1.join()方法,所以主线程需要等待子线程1完成之后再继续执行,而不需要等待子线程2执行完成。
执行结果:
3. yield()
这个方法只是提出申请释放CPU资源,至于能否成功释放由JVM决定,也就是说该线程会回到就绪状态(RUNABLE),随时可能被CPU调度到。
简单来说就是提示CPU,我这个线程主要的内容执行完了,CPU可以将时间片拿去给其他线程使用,但只是给出一个建议信息,建议CPU去调度同级线程中优先级更高的线程。
4. setPriority()
设置线程的优先级,默认为5,线程优先级在1-10之间,有set方法一般就会有get方法,默认情况下,getPriority()就会返回默认的线程优先级5,源码如下:
代码语言:javascript复制 /**
* The minimum priority that a thread can have.
*/
public final static int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.
*/
public final static int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.
*/
public final static int MAX_PRIORITY = 10;
如果设置线程优先级大于10或者是小于1,会抛出IllegalArgumentException,这点也在setPriority()中可以找到。
代码语言:javascript复制if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
虽然设置了线程优先级,但是在线程数没有达到电脑最大线程数的时候,线程优先级高的不一定先执行完成。
代码语言:javascript复制 Thread thread1 = new Thread(()->{
System.out.println("子线程1执行完了");
});
Thread thread2 = new Thread(()->{
System.out.println("子线程2执行完了");
});
thread2.setPriority(6);
thread2.start();
thread1.start();
大多数情况下都是线程2先执行完,但是也有极少数情况下,会是线程1先执行完。
5. setName()
设置线程名称,两种方式可以设置,一是在创建线程的时候通过构造方法传入,第二种是通过setName()方法传入。当然不传的时候,也会有线程的默认的名字。
代码语言:javascript复制 Thread thread1 = new Thread(()->{
System.out.println("子线程1执行完了");
});
Thread thread2 = new Thread(()->{
System.out.println("子线程2执行完了");
});
Thread thread3 = new Thread(()->{
System.out.println("子线程3执行完了");
},"线程3");
thread2.setName("线程2");
thread2.start();
thread1.start();
thread3.start();
System.out.println("线程1的名称:" thread1.getName());//Thread-0
System.out.println("线程2的名称:" thread2.getName());//线程2
System.out.println("线程2的名称:" thread3.getName());//线程3
6. currentThread()
获取当前线程,得到一个Thread类。
代码语言:javascript复制 Thread thread1 = new Thread(()->{
String name = Thread.currentThread().getName();
System.out.println(name);
});
thread1.start();
String name = Thread.currentThread().getName();
System.out.println(name);
7. setDaemon()
设置该线程为守护线程,参数为布尔值。所谓守护线程就是为用户线程服务的线程,比如说垃圾回收的线程等等,当用户线程结束,守护线程完成任务之后自动结束,我们正常创建的线程即为用户线程,使用Thread.setDaemon(true)方法, 线程变成守护线程 。如果用户希望主线程结束之后,其他线程自动结束,则可以将其他线程设置为守护线程。
代码语言:javascript复制public final void setDaemon(boolean on) {
checkAccess();
if (isAlive()) {
throw new IllegalThreadStateException();
}
daemon = on;
}
isAlive()方法判断线程是否存活,那么setDaemon()中调用这个方法的意思就是,如果线程存活的话,就会抛出不合法的线程状态异常。所以就限制了,调用setDaemon()方法必须在调用start()方法之前,否则就会抛出异常。
8. interrupt()
利用这个方法可以中断线程,值得注意的是,如果该线程处于等待,阻塞,或者无限期等待状态,那么就会抛出InterruptedException异常,从而提前结束线程。但是不能中断I/O阻塞和synchronized锁阻塞。
先看看等待,阻塞的情况;
sleep方法
代码语言:javascript复制 Thread thread = new Thread(()->{
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
thread.interrupt();
会抛出异常 java.lang.InterruptedException: sleep interrupted
wait方法
代码语言:javascript复制 public class InterruptTest {
private static String str = "test";
public static void main(String[] args) {
Thread thread = new Thread(()->{
synchronized (str){
try {
str.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
thread.interrupt();
}
}
抛出异常:java.lang.InterruptedException
join方法
代码语言:javascript复制 Thread thread1 = new Thread(()->{
while (true){
}
});
Thread thread = new Thread(()->{
try {
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread1.start();
thread.start();
thread.interrupt();
抛出异常:java.lang.InterruptedException
synchronized锁阻塞测试:
代码语言:javascript复制 public class InterruptTest {
private static String str = "test";
public static void main(String[] args) {
Thread thread = new Thread(() -> {
synchronized (str) {
while (true){
}
}
});
thread.start();
thread.interrupt();
}
}
这段代码会一直执行下去,不会被中断,也不会抛出异常。关于线程中断的东西后面再写一篇文章,点个关注不迷路。