一、简介
本文主要介绍Obejct类的wait, notify, notifyAll, Thread类的sleep, join, yield, setPrority, isDaemon 等相关方法的使用细节。
二、常用方法
2.1 wait
2.1.1 使用细节
- 使当前线程进入阻塞状态;
- 释放锁;
2.1.2 案例
- 略
2.2 notify
2.2.1 使用细节
- 唤醒单个线程;
2.2.2 案例
- 略
2.3 notifyall
2.3.1 使用细节
- 唤醒所有线程;
2.3.2 案例
- 略
2.4 sleep
2.4.1 使用细节
- 使得当前线程进入阻塞状态,休眠指定时间,时间过期后会自动进入RUNNING(就绪)状态;
- 不释放锁
2.4.2 案例
2.5 yield
2.5.1 使用细节
- 使得当前线程让步,从运行状态变为Runnable的就绪状态,从而使得该线程与该线程相同优先级或更高优先级的线程一起再次竞争;
- 线程执行了yield方法后,也有可能继续执行该线程;
- yield方法不会释放锁;
2.5.2 案例
- 略
2.6 join
2.6.1 使用细节
- join的意思是使得当前线程放弃执行,转而执行新加入的线程;
- 如果带时间参数,则该时间内执行新加入的线程,该时间之后之前的主线程和新加入的线程竞争执行;
- 如果不带时间参数,则当前线程放弃执行,一直等待新加入的线程指向完毕之后再开始执行;
- join(0)相当于无参,而非0秒之后开始交替执行竞争;
- A线程中join了B线程,则join会将线程A的锁给释放了然后交替执行。
2.6.2 案例1
- 代码
/**
* @author qjwyss
* @date 2019/4/8
* @description
*/
public class JoinDemo {
public static void main(String[] args) {
try {
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "输出值:" + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "线程1");
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "输出值:" + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "线程2");
thread1.start();
// 有参:main线程中join了线程1,并且带时间参数,则前3秒内先执行线程1,然后线程1和main线程(j即后面的线程2)交替执行。
thread1.join(3000);
// 无参:main线程中join了线程1,则main线程会先暂停,然后先执行线程1,当线程1执行完之后,才开始执行main线程,在main线程中执行了线程2
// thread1.join();
// 有参为0:相当于无参
// thread1.join(0);
thread2.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
- 无参和参数为0输出结果:
-
线程1输出值:0 线程1输出值:1 线程1输出值:2 线程1输出值:3 线程1输出值:4 线程2输出值:0 线程2输出值:1 线程2输出值:2 线程2输出值:3 线程2输出值:4
- 有参输出结果:
-
线程1输出值:0 线程1输出值:1 线程1输出值:2 线程2输出值:0 线程1输出值:3 线程2输出值:1 线程1输出值:4 线程2输出值:2 线程2输出值:3 线程2输出值:4
2.6.3 案例2
-
代码
-
/** * @author qjwyss * @date 2019/4/9 * @description */ public class JoinDemo2 { public static void main(String[] args) { Thread parentThread = new Thread(() -> { Thread childThread = new Thread(() -> { for (int i = 0; i < 6; i++) { try { Thread.sleep(1000); System.out.println(Thread.currentThread().getName() + "输出值:" + i); } catch (InterruptedException e) { e.printStackTrace(); } } }, "子线程"); childThread.start(); try { childThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 5; i++) { try { Thread.sleep(1000); System.out.println(Thread.currentThread().getName() + "输出值:" + i); } catch (InterruptedException e) { e.printStackTrace(); } } }, "父线程"); parentThread.start(); } }
-
结果
-
子线程输出值:0 子线程输出值:1 子线程输出值:2 子线程输出值:3 子线程输出值:4 父线程输出值:0 父线程输出值:1 父线程输出值:2 父线程输出值:3 父线程输出值:4
2.7 setPrority
2.7.1 使用细节
- java中线程的优先级范围是:1~10, 默认为5;
- 优先级越高,获取CPU的可能性越大,但并非优先级越高就先执行;
2.7.2 案例
- 无
2.8 setDaemon
2.8.1 使用细节
- java中有俩种线程:用户线程和守护线程。用户线程一般用于执行用户级任务,守护线程即后台线程,一般用于执行后台任务;
- 可以用isDaemon()方法来区分是否为守护线程;
- 当JVM启动时,通常有一个单一的非守护线程(即用main方法启动的线程),jvm会一致运行下去直到遇见下面俩种清空之一才会退出:
- 调用了exit()方法,并且exit()方法有权限被执行;
- 所有的非守护线程都死了,即只剩下守护线程;
2.8.2 案例
- 无
三、多线程系列链接
- 多线程系列(一)------ 线程的状态及转换
- 多线程系列(二)------ 线程的创建方式
- 多线程系列(三)------ 线程常用方法
- 多线程系列(四)------ 线程优先级和守护线程和终止线程的方式
-
多线程系列(六)------ 生产者消费者案例
- 多线程系列(七)------ synchronized关键字简单使用以及可重入性
- 多线程系列(八)------ synchronized关键字原理以及锁优化
- volatile相关
- ThreadLocal相关
- 锁LOCK相关系列
- 原子类相关系列
- 并发集合相关系列
- 线程池相关系列