一、通用的线程生命周期
1、初始状态:线程被创建,但是还允许被分配cpu执行。
2、可运行状态:线程可以分配cpu执行。
3、运行状态:线程正在被cpu执行。
4、休眠状态:运行的时候,如果被阻塞或者等待某个事件,就会从运行状态转为休眠状态,同时释放cpu资源,如果等到了事件,则会转为可运行状态;
5、结束状态:线程运行完成或者出现异常。
二、Java的线程生命周期
线程的六个状态如上图所示(呱唧呱唧,好看)
new:创建一个线程,为线程分配内存并初始化其成员变量的值;
runnable:start方法之后将转为就绪状态,此时jvm完成了方法调用栈和程序计数器的创建,等待该线程的调度和运行;
running:争取到cpu资源,开始执行run方法;
blocked:同步阻塞,未获取到同步锁;
waiting/timed_waiting:等待阻塞
2.1 创建线程的方式
(1)、继承thread方法,重写run方法
package exercise_03_0712_thread;
public class ThreadTest1 extends Thread {
@Override
public void run() {
System.out.println("thread is run~");
}
public static void main(String[] args) {
ThreadTest1 threadTest1 = new ThreadTest1();
threadTest1.start();
}
}
(2)、实现runnable接口,重写run方法
package exercise_03_0712_thread;
public class ThreadTest2 implements Runnable {
@Override
public void run() {
System.out.println("thread is run~");
}
public static void main(String[] args) {
Thread thread = new Thread(new ThreadTest2());
thread.start();
}
}
(3)通过ExcutorService和Callable 实现有返回值的线程
package exercise_03_0712_thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class ThreadTest3 implements Callable<String> {
private String name;
public ThreadTest3(String name) {
this.name = name;
}
@Override
public String call() throws Exception {
System.out.println(Thread.currentThread().getName() + " call");
return name;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService threadPool = Executors.newFixedThreadPool(2);
List<Future> list = new ArrayList<>();
for (int i = 0; i < 2; ++i) {
Callable callable = new ThreadTest3(i + "");
// 提交线程
Future future = threadPool.submit(callable);
System.out.println("submit thread : " + i);
list.add(future);
}
// 关闭线程池
threadPool.shutdown();
// 遍历所有线程的结果
for (Future future : list) {
System.out.println("get future result: " + future.get().toString());
}
}
}
(4)基于线程池
package exercise_03_0712_thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadTest4 {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(2);
for (int i = 0; i < 2; ++i) {
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " is run");
}
});
}
threadPool.shutdown();
}
}
2.2 线程的启动
start和run方法的区别?
源码:
run方法:在独立执行的线程中被调用。
start方法在jvm会做两个比较重要的事情:
(1)、new一个java 线程,os::create_Thread();
(2)、调用Thread::start去启动刚才构造的线程,并把它的状态置为RUNNABLE;
所以,线程的start是基于操作系统去构造一个线程的启动,回调run方法,把它的状态置为RUNNABLE。
代码验证:
start:
run:
(1)、start方法启动一个线程时,线程处于就绪状态,并没有运行。而调用run方法,线程就会进入运行状态,开始运行run方法里的代码,在run方法运行结束后,cpu再调度其他线程。
(2)、在调用了start之后,线程会在后台执行,无需等待run方法执行完毕。
2.3 线程的终止
(1)、正常运行结束
即run方法执行完毕
(2)、使用退出标志终止线程
用一个变量来控制循环,变量用volatitle修饰,可保证线程安全。
private volatile static boolean flag = true;
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " thread is run~");
while (flag) {
System.out.println("running");
}
System.out.println(Thread.currentThread().getName() + " thread is over~");
}
(3)、使用interrupt方法终止线程
a、线程处于阻塞状态时,调用interupt,会抛出异常
package exercise_03_0712_thread;
public class InterruptedTest extends Thread{
@Override
public void run() {
while (!isInterrupted()) {
System.out.println("run");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
public static void main(String[] args) throws InterruptedException {
InterruptedTest interruptedTest = new InterruptedTest();
interruptedTest.start();
Thread.sleep(1000);
interruptedTest.interrupt();
}
}
捕捉这个异常,然后进行退出。
b、线程不处于阻塞状态,调用interrupt,线程中可以使用isinterrupted来判断是否终止线程。
线程默认的interrupted值为false;
调用了interrupt(),interrupted就会变成true;
package exercise_03_0712_thread;
public class InterruptedTest extends Thread{
@Override
public void run() {
while (!isInterrupted()) {
System.out.println("run");
}
}
public static void main(String[] args) throws InterruptedException {
InterruptedTest interruptedTest = new InterruptedTest();
interruptedTest.start();
Thread.sleep(1000);
interruptedTest.interrupt();
}
}
(2)、使用stop,不建议使用,已过期
stop杀死线程,如果线程含有synchronized锁,也不会释放。
2.3 线程的复位
第一种:Thread.interrupted()
package exercise_03_0712_thread;
public class InterruptedTest extends Thread{
@Override
public void run() {
while (true) {
if (isInterrupted()) {
System.out.println("before: " + Thread.currentThread().isInterrupted());
Thread.interrupted();//复位,回到原始状态
System.out.println("after: " + Thread.currentThread().isInterrupted());
}
}
}
public static void main(String[] args) throws InterruptedException {
InterruptedTest interruptedTest = new InterruptedTest();
interruptedTest.start();
Thread.sleep(1000);
interruptedTest.interrupt();
}
}
第二种:异常
正在阻塞中的线程被中断,会抛异常的,也会让线程的interrupted标记复位。
package exercise_03_0712_thread;
public class InterruptedTest extends Thread{
@Override
public void run() {
while (!isInterrupted()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("isInterrupted: " + isInterrupted());
break;
}
}
}
public static void main(String[] args) throws InterruptedException {
InterruptedTest interruptedTest = new InterruptedTest();
interruptedTest.start();
Thread.sleep(1000);
interruptedTest.interrupt();
}
}