线程状态
1)、新建(NEW):在jvm上new出一个Thread的实例,还没有调用start()方法;
2)、运行(RUNNABLE):运行状态又分为两个状态,就绪和运行中,当CPU为线程分配时间片时,线程进入运行中状态;如果不为线程分配时间片,则进入就绪状态,等待CPU分配时间片。当然,运行中的线程调用yield()也会将线程变成就绪状态;
3)、等待(WAITING):线程调用wait()/join(),进入等待状态,需要调用notify()/notifyAll()才能被唤醒再次进入运行状态;
4)、定时等待(TIMED_WAITING):线程调用sleep(long)/wait(long)/join(long),进入定时等待状态,当达到等待时间或者调用notify()/notifyAll()时,再次进入运行状态;
5)、阻塞(BLOCKED):多个线程运行,竞争某个synchronized(内置锁)的模块,只有一个线程能获得这个锁,其他线程会进入阻塞状态,当线程获取锁时,该线程从阻塞状态编程可运行状态;
6)、结束(TERMINATED):线程执行完或者抛出异常提前结束。
线程常用方法
start()和run()
start()是真正意义上的启动了操作系统的线程,线程进入就绪队列,等待CPU分配时间片,获取到时间片后才会执行线程中的run(),start()只能执行一次,重复执行会报错;
run()本质上是业务逻辑的实现方法,所以run(),与接口实现类中的实现方法一样,可以重复执行;
package com.su.mybatis.oracle.controller;
public class Main {
public static void main(String[] args) throws InterruptedException {
TestThread t1 = new TestThread();
t1.setName("Test");
t1.start();
TestThread.sleep(100);
t1.run();
TestThread.sleep(100);
t1.run();
}
}
class TestThread extends Thread{
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println("线程(" + threadName + ")已启动");
}
}
输出结果:
线程(Test)已启动
线程(main)已启动
线程(main)已启动
结果也验证了:1、线程启动的真正方法是start();2、run()可多次执行。
yield()
将线程从运行中状态线程变成就绪状态,让出cpu的执行权,并通知操作系统,操作系统从就绪线程中选出线程执行。可以选择原来执行yield()的线程。需要注意的是让出时间不可设定,不会释放资源。
应用场景:比如一个资源初始化方法,该方法允许多个线程同时进入,但是为了保证线程安全,只允许一个线程对这个资源进行初始化。当多个线程进入该方法时,只需要第一个线程对资源进行初始化,其他线程不需要执行,此时可以使用Thread.yield()让出cpu执行权,不进行初始化。
join()
将指定线程加入到当前线程,先执行完指定线程,再执行当前线程,理解为插队即可。
举个例子:
package com.su.mybatis.oracle.controller;
public class Main {
public static void main(String[] args) throws InterruptedException {
EatRunnable e = new EatRunnable();
Thread te = new Thread(e);
te.start();
// te.join();
System.out.println("开始睡觉...");
Thread.sleep(3000);
System.out.println("结束睡觉...");
}
}
class EatRunnable implements Runnable{
@Override
public void run() {
try {
System.out.println("开始吃饭...");
Thread.sleep(3000);
System.out.println("结束吃饭...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出结果:
开始睡觉...
开始吃饭...
结束睡觉...
结束吃饭...
睡觉吃饭几乎是同时开始,同时结束。
加上te.join();后(去掉前面的//),输出结果:
开始吃饭...
结束吃饭...
开始睡觉...
结束睡觉...
先吃完饭,再睡觉。
如果有写的不对的地方,请大家多多批评指正,非常感谢!