一. 线程的五大状态:
新建状态:使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态,它保持这个状态直到程序 start() 这个线程。
就绪状态:当线程对象调用了start()方法之后,该线程就进入就绪状态,就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。
运行状态:如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态,处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。
阻塞状态:如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态,在睡眠时间已到或获得设备资源后可以重新进入就绪状态。
死亡状态:一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
二. Thread类中的常用方法:
public void start() : 使该线程开始执行,Java 虚拟机调用该线程的 run 方法。
public void run() : 如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法,否则,该方法不执行任何操作并返回。
public final void setName(String name) : 改变线程名称,使之与参数 name 相同。
public final void setPriority(int priority) : 更改线程的优先级。
public int getPriority() : 获取线程的优先级。
public final void setDaemon(boolean on) : 将该线程标记为守护线程或用户线程。
public void interrupt() : 中断线程。
public final void join(long millisec) : 等待该线程终止的时间最长为 millis 毫秒。
public final boolean isAlive() : 测试线程是否处于活动状态。
public static void yield() : 暂停当前正在执行的线程对象,并执行其他线程。
public static void sleep(long millisec) : 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
三. 常用方法举例:
① 线程停止:
建议使用标志位,使线程正常停止
不要使用stop或者destory等过时或JDK不建议使用的方法
public class TestStop implements Runnable{
private boolean flag = true; // 设置一个标志位
@Override
public void run() {
int i = 0;
while (flag){
System.out.println("run...Thread..."+i++);
}
}
// 设置一个公开的方法停止线程,转换标志位
public void stop(){
this.flag = false;
}
public static void main(String[] args) {
TestStop testStop = new TestStop();
new Thread(testStop).start();
for (int i = 0; i < 1000; i++) {
System.out.println("main Thread..."+i);
if (i==900){
testStop.stop();
System.out.println("线程该停止了!");
}
}
}
}
② 线程休眠——sleep():
sleep()方法存在异常InterruptedException
sleep()方法时间达到后线程进入就绪状态
每个都有一把锁,sleep方法不会释放锁
public class TestSleep{
public static void main(String[] args) {
try {
Delay();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 模拟延时
public static void Delay() throws InterruptedException {
for (int i = 0; i < 5; i++) {
System.out.println(new Date());
Thread.sleep(2000);
}
}
}
结果:
Fri Feb 19 20:19:35 CST 2021
Fri Feb 19 20:19:37 CST 2021
Fri Feb 19 20:19:39 CST 2021
Fri Feb 19 20:19:41 CST 2021
Fri Feb 19 20:19:43 CST 2021
③ 线程礼让(暂停)——yield():
礼让线程,yield()方法暂停正在执行的线程,但不堵塞
将线程从运行状态转为就绪状态
暂停正在执行的线程后,CPU重新调度新的线程,礼让(暂停)不一定成功!
package Thread;
public class TestYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程开始了");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"线程结束了");
}
public static void main(String[] args) {
TestYield testYield = new TestYield();
new Thread(testYield,"a").start();
new Thread(testYield,"b").start();
}
}
注释掉yield()方法的结果:
a线程开始了
a线程结束了
b线程开始了
b线程结束了
没有注释的结果:
a线程开始了
b线程开始了
b线程结束了
a线程结束了
④ 线程强制执行——join():
join合并线程,待此线程完成后再执行其他线程,其他线程堵塞
可以想象成插队
可以给它一个时间参数join(long time),表示最多等待time毫秒
public class TestJoin implements Runnable{
@Override
public void run() {
try {
Thread.sleep(1000); // 延时1秒让主线程先走
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 5; i++) {
System.out.println("线程vip来了..."+i);
}
}
public static void main(String[] args) throws InterruptedException {
TestJoin testJoin = new TestJoin();
Thread thread = new Thread(testJoin);
thread.start();
for (int i = 0; i < 10; i++) {
if (i==5)
thread.join();
System.out.println("main线程..."+i);
}
}
}
结果:
main线程...0
main线程...1
main线程...2
main线程...3
main线程...4
线程vip来了...0
线程vip来了...1
线程vip来了...2
线程vip来了...3
线程vip来了...4
main线程...5
main线程...6
main线程...7
main线程...8
main线程...9
⑤ 观测线程状态——isAlive():
线程可以处于下列状态之一:
NEW:至今尚未启动的线程处于这种状态
RUNNABLE:正在 Java 虚拟机中执行的线程处于这种状态
BLOCKED:受阻塞并等待某个监视器锁的线程处于这种状态
WAITING:无限期地等待另一个线程来执行某一特定操作的线程处于这种状态
TIMED_WAITING:等待另一个线程来执行取决于指定等待时间的操作的线程处于这种状态
TERMINATED:已退出的线程处于这种状态
public class TestState {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{ // lambda表达式
for (int i = 0; i < 5; i++) { // 延时5秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("======");
});
// 观察线程状态
Thread.State state = thread.getState(); // 获取当前线程的状态
System.out.println(state); // NEW
thread.start(); // 启动线程
state = thread.getState();
System.out.println(state); // RUNNABLE
if (thread.isAlive()){ // 判断线程是否处于活动状态
System.out.println("此时的状态为RUNNABLE");
}
while (state!=Thread.State.TERMINATED){ // 只要线程没有结束
Thread.sleep(500); // 等半秒再观察
state = thread.getState(); // 更新状态
System.out.println(state);
}
}
}
结果:
NEW
RUNNABLE
此时的状态为RUNNABLE
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
======
TERMINATED
⑥ 线程的优先级——setPriority(int priority)、getPriority():
线程的优先级用数字表示,范围为[1,10]
Thread.MAX_PRIORITY=10
Thread.MIN_PRIORITY=1
Thread.NORM_PRIORITY=5 (默认值)
优先级越高获得调度的概率越大
public class TestPriority {
public static void main(String[] args) {
// 打印主线程优先,应为默认优先级 5
System.out.println(Thread.currentThread().getName()+"的优先级--->"+Thread.currentThread().getPriority());
MyPriority myPriority = new MyPriority();
Thread t1 = new Thread(myPriority);
Thread t2 = new Thread(myPriority);
Thread t3 = new Thread(myPriority);
Thread t4 = new Thread(myPriority);
// 先设置优先级再启动
t1.setPriority(Thread.MAX_PRIORITY);
t1.start();
t2.setPriority(Thread.MIN_PRIORITY);
t2.start();
t3.setPriority(4);
t3.start();
t4.setPriority(8);
t4.start();
}
}
class MyPriority implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"的优先级--->"+Thread.currentThread().getPriority());
}
}
结果:
main的优先级--->5
Thread-0的优先级--->10
Thread-3的优先级--->8
Thread-2的优先级--->4
Thread-1的优先级--->1
⑦ 守护线程——setDaemon(boolean on):
线程分为用户线程和守护线程
虚拟机必须确保用户线程执行完毕,不用等待守护线程执行完毕
setDaemon(boolean on):当on为true,则设置线程为守护线程,否则反之,默认为false
守护线程用于后台记录操作日志、监控内存、垃圾回收等待等等
public class TestSetDaemon {
public static void main(String[] args) {
God god = new God();
You you = new You();
Thread thread = new Thread(god);
// 设置为守护线程
thread.setDaemon(true); // 默认为false
thread.start();
new Thread(you).start(); // 用户线程
}
}
class God implements Runnable{
@Override
public void run() {
while (true){
System.out.println("-----上帝守着你-----");
}
}
}
class You implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Happy Every Day");
}
}
}
结果:
-----上帝守着你-----
-----上帝守着你-----
-----上帝守着你-----
-----上帝守着你-----
-----上帝守着你-----
-----上帝守着你-----
Happy Every Day
Happy Every Day
Happy Every Day
Happy Every Day
Happy Every Day
Happy Every Day
Happy Every Day
Happy Every Day
Happy Every Day
Happy Every Day
-----上帝守着你-----
-----上帝守着你-----
-----上帝守着你-----
-----上帝守着你-----
...