线程状态转换以及基本操作
思维导图
1.新建线程
1.1 Java程序天生就是一个多线程程序,包含了
- 分发处理发送给JVM信号的线程
- 调用对象的
finalize()
方法的线程 - 清除Reference的线程
- main线程,用户程序的入口
1.2 如何新建线程
- 继承Thread类,重写run方法
- 通过实现Runable接口
- 通过实现Callable接口
演示:
package bingfang.git_boke_code.Two;
import java.util.concurrent.*;
public class CreateThreadDemo {
public static void main(String[] args) {
//1.继承Thread
Thread thread = new Thread(){
@Override
public void run() {
System.out.println("继承Thread");
super.run();
}
};
thread.start();
//2.实现Runable接口
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("实现Runable接口");
}
});
thread1.start();
//3.实现callable接口
ExecutorService service = Executors.newSingleThreadExecutor();
Future<String> future = service.submit(new Callable(){
@Override
public Object call() throws Exception {
return "通过实现Callable接口";
}
});
try{
String result = future.get();
System.out.println(result);
}catch (InterruptedException e){
e.printStackTrace();
}catch (ExecutionException e){
e.printStackTrace();
}
}
}
2.线程状态转换
2.1 线程的状态
-
NEW
:初始状态,线程被构建,但还没有调用start()方法 -
RUNNABLE
:运行状态,Java将操作系统中的就绪和运行两种状态笼统的称为运行中 -
BLOCKED
:阻塞状态,表示线程阻塞于锁 -
WAITING
:等待状态,线程进入等待状态,表示线程需要等待其他线程做出一些特定动作 -
TIME_WAITING
:超时等待状态,该状态不同于WAITING,可以在指定时间自行返回 -
TERMINATED
:终止状态,表示该线程已经执行完毕
3.线程基本操作
3.1 interrupted
- 中断可以理解为线程的一个标志位,它表示一个运行中的线程是否被其他线程执行了中断操作。中断好比其他线程对该线程打了一个招呼。
- 其他线程可以调用
interrupt()
方法对其进行中断操作,同时该线程可以用isInterrupted()
方法感知其他线程对它的中断操作,从而做出响应。当一个线程在执行Object.wait()
/Object.wait(long)
,Sleep(long)
,join()
/join(long)
方法时被中断会抛出Interrupted exception
异常 - 另外,也可以调用
Thread
的Interrupted()
方法对线程进行中断,该方法会清除中断标志位,也就是说在调用isInterrupted()
时会返回false。
演示:Main线程去中断sleepThread,sleepThread的中断标志位清零(变为false)并抛出java.lang.InterruptedException: sleep interrupted
异常
package bingfang.git_boke_code.Two;
public class InterruptDemo {
public static void main(String[] args) throws InterruptedException{
//sleepThread 睡眠 1000ms
final Thread sleepThread = new Thread(){
@Override
public void run() {
try{
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
super.run();
}
};
//busyThread一直执行死循环
Thread busyThread = new Thread(){
@Override
public void run() {
while (true);
}
};
sleepThread.start();
busyThread.start();
sleepThread.interrupt();//Main线程去中断sleepThread,sleepThread
//的中断标志位清零(变为false)
busyThread.interrupt();
while(sleepThread.isInterrupted());
System.out.println("sleepThread isInterrupted:"+
sleepThread.isInterrupted());
System.out.println("busyThread isInterrupted:" +
busyThread.isInterrupted());
}
}
输出结果:
sleepThread isInterrupted: false
busyThread isInterrupted: true
3.2 join
- 概述
- join方法可以看成线程间协作的一种方式,如果一个线程实例A执行
ThreadB.join()
,其含义为:当前线程A会等待ThreadB执行完成后(终止后)再继续执行。
- Thread类除了提供join()方法外,另外还提供了超时等待的方法,如果线程ThreadB在等待时间内还没有结束的话,ThreadA会在超时之后继续执行。(不再继续等下去)
演示:
package bingfang.git_boke_code.Two;
public class JoinDemo {
public static void main(String[] args) {
Thread previousThread = Thread.currentThread();
for(int i = 0; i < 10; i++){
JoinThread curThread = new JoinThread(previousThread);
curThread.start();
previousThread = curThread;
}
}
static class JoinThread extends Thread{
Thread thread;
public JoinThread(Thread thread){
this.thread = thread;
}
@Override
public void run() {
try{
thread.join();
System.out.println(thread.getName()+"terminated");
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
/*public static void main(String[] args) {
Thread previousThread = Thread.currentThread();
for(int i = 1; i <= 10; i++){
Thread curThread = new JoinThread(previousThread);
curThread.start(); //curThread启动后会调用
//previousThread的join方法
//意思就是说curThread会等待
//previousThread执行完再继续执行
previousThread = curThread;
}
}
static class JoinThread extends Thread{
private Thread thread;
public JoinThread(Thread thread){
this.thread = thread;
}
@Override
public void run() {
try{
thread.join();
//执行了previousThread的join方法
//就是说当前线程会等待previousThread
//执行完后再继续执行
System.out.println(thread.getName()+"terminated");
}catch (InterruptedException e){
e.printStackTrace();
}
}
}*/
}
运行结果:
mainterminated
Thread-0terminated
Thread-1terminated
Thread-2terminated
Thread-3terminated
Thread-4terminated
Thread-5terminated
Thread-6terminated
Thread-7terminated
Thread-8terminated
3.3 sleep
- 概念:是Thread的静态方法,作用是让当前线程按照指定的时间休眠,其休眠时间的精度取决于处理器的计时器和调度器。需要注意的是当前线程持有锁时,sleep并不会让当前线程失去锁
- sleep()与Object.wait()方法对比
- 1.sleep()是Thread的静态方法,而wait是Object的实例方法
- 2.wait()方法必须在同步方法或者同步块中调用,也就是必须已经获得对象锁。而sleep()没有限制可以在任一情况下使用。另外,wait()方法会释放线程持有的对象锁,使线程重新进入等待池中,等待下一次获取资源。而sleep()只会让出CPU而不会释放掉对象锁。
- sleep()方法在休息时间完成之后如果再次获得CPU时间片就会继续执行,而wait()方法必须等待
Object.notify
/Object.notifyAll
通知后,才会离开等待池,并且再次获得CPU时间片后才会继续执行
3.4 yield
- 概念:
yield()
是一个静态方法,一旦执行,它会让当前线程让出CPU,但让出CPU并不代表就不执行了,而是让让出CPU的线程和其他线程再次竞争,如果在下一次竞争中获得了时间片,当前线程依然会继续执行。另外让出的时间片只会分配给当前线程相同优先级的线程。 - 线程优先级
- 概念:线程优先级就是线程会或多或少分配一些处理器资源的线程属性
- 在Java程序中,通过一个整型成员变量
Priority
来控制优先级,优先级的范围从1-10。在构建线程的时候,可以通过setPriority(int)
方法设置线程优先级,默认优先级为5.优先级高的线程比优先级低的线程优先获得处理器时间片。需要注意的是在某些JVM和操作系统上线程规划存在差异,有些操作系统甚至会忽略优先级的设定 - 另外,
sleep()
和yield()
方法,同样都是当前线程会交出处理器资源,但它们不同的是,sleep()
交出的时间片其他线程都可以去竞争,即都有机会获得当前线程交出的时间片;而yield()
只允许与当前线程具有相同优先度的线程能够获得释放出的时间片
4.守护线程Daemon
- 守护线程是一种特殊的线程,就和它的名字一样,它是系统的守护者,在后台默默守护着一些系统服务,比如垃圾回收线程,JIT线程就可以理解为守护线程。线程可以通过
setDeamon(true)
将线程设置为守护线程,但需要注意的是设置守护线程必须优先于start()
方法,否则会报java.lang.IllegalThreadStateException
错误 - 与守护线程对应的就是用户线程,用户线程就是系统的工作线程,他会完成整个系统的业务操作。用户线程结束后,系统中就没有对象需要守护了,守护线程也自然会结束。当一个Java程序只有守护线程时,虚拟机就会自然退出
- 守护线程在退出时并不会执行finally块中的代码,所以释放资源等操作不要放在finally块中,这种操作是不安全的。
演示:
package bingfang.git_boke_code.Two;
public class DaemonDemo {
public static void main(String[] args) {
Thread daemonThread = new Thread(new Runnable() {
@Override
public void run() {
while(true){
try{
System.out.println("i am alive");
Thread.sleep(500);
}catch (InterruptedException e){
e.printStackTrace();
}finally {
System.out.println("finally block");
}
}
}
});
daemonThread.setDaemon(true);
daemonThread.start();
try{
Thread.sleep(800);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
运行结果:
i am alive
finally block
i am alive
若把deamonThread的sleep时间由Thread.sleep(500);
改为Thread.sleep(1000);
运行结果为:
i am alive
明显看出Main线程结束后daemonThread没有执行finally块的内容。
小结:
简单介绍了如何新建线程,线程的6种状态,4种基本操作以及守护线程Deamon的概念。
参考资料
1. github:Java-concurrency-master
2.《Java并发编程的艺术》