文章目录
1、线程的状态
Java中线程的状态由6种,Thread类中的内部类State来体现
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
NEW(新建状态)
:new Thread()
创建线程对象。RUNNABLE(就绪状态)
:线程对象此时调用start()
方法,此时在JVM进程中创建了一个线程,线程并不是一经创建就直接得到执行,需要等待操作系统的其他资源,比如:处理器。BLOCKED(阻塞状态)
:等到一个监视器锁进入到同步代码块或者同步方法中,代码块/方法某一个时刻只允许一个线程去执行,其他线程只能等待,这种情况下等待的线程会从RUNNABLE状态
转换到BLOCKED状态
;例如Object.wait()
方法。WAITING(等待状态)
:调用Object.wait()/join()/LockSupport.park()
等方法,此时线程从RUNNABLE状态
转换到WAITING状态
。TIMED_WAITING(睡眠状态)
:调用带超时参数的Thread.sleep(long millis)/Object.wait(long timeout)/join(long millis)/LockSupport.parkNanos()/LockSupport.parkUntil()
等方法都会使得当前线程进入到TIMED_WAITING状态
。TERMINATED(终止状态)
:是线程的最终状态。
1、线程正常运行结束。
2、线程运行出错。
3、JVM crash。
2、线程间的状态转化
3、线程常用方法
(1)start()
启动一个线程,将线程添加到一个线程组中,线程状态会从New状态转换到Runnable状态
public class TestDemo {
public static void main(String[] args) {
Thread thread = new Thread(){
@Override
public void run() {
try {
Thread.sleep(5000);
System.out.println("子线程运行结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
}
}
(2)sleep()
sleep是一个静态方法,其中存在两个重载函数
public static native void sleep(long millis)
public static void sleep(long millis,int nanos)
sleep方法使得当前线程指定毫秒级的休眠,暂停执行,不会放弃monitor lock的使用权。
jdk1.5之后,引入枚举类型TimeUnit
,对sleep方法对其进行了封装,省去了时间单位换算的步骤。
TimeUnit.HOURS.sleep(3); //睡眠3个小时
TimeUnit.MINUTES.sleep(27); //睡眠27分钟
TimeUnit.SECONDS.sleep(8); //睡眠8秒种
TimeUnit.MILLISECONDS.sleep(88);//睡眠88毫秒
public class TestDemo {
public static void main(String[] args) {
new Thread(){
@Override
public void run() {
try {
// Thread.sleep(5000);
TimeUnit.MILLISECONDS.sleep(88);//睡眠88毫秒
System.out.println("子线程运行结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
try {
// Thread.sleep(200);
TimeUnit.MILLISECONDS.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程运行结束");
}
}
(3)yield()
属于启发式的方法。线程A.yield()
会提醒调度器线程A愿意放弃本次的cpu资源,如果cpu资源不紧张,处理器有可能会忽略这种提示。
public class TestDemo {
public static void main(String[] args) {
new Thread(){
@Override
public void run() {
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.yield();
try {
Thread.sleep(1000);
System.out.println("Main Thread Finished");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
问题1:调用yield方法线程进行让步,OS进行调度的下一个线程有没有可能是刚让步的线程? 会
问题2:yield方法为什么是static修饰的静态方法,而不用创建的对象调用yield方法呢?通过线程对象来调用yield方法呢?
yield方法用来使正在执行的线程让出CPU的使用权,如果是通过线程对象(new Thread)调用yield方法,会使大家产生错觉:认为是让当前的线程对象让步。当前的线程对象(调用yield方法的线程)不等同于正在执行的线程(占用CPU资源的线程)。所以采用Thread.yield
调用方式,让使用者区分清楚是让正在执行的线程让出CPU的使用权
问题3:yield()和sleep()的区别?
- JDK1.5之前,yield调用sleep
- sleep() 方法声明抛出 InterruptedException;yield() 方法没有声明抛出异常
- sleep使得当前线程暂停执行,不会占用CPU资源,yield只是堆CPU调度器的一个提示
- sleep会导致线程短暂的阻塞,yield会使得线程转入就绪状态,可能马上又得得到执行
(4)join()
多线程的执行时并发执行,线程的执行顺序是不可控的。join方法提供将并发执行合并成串行执行,即让线程能够有序的执行。
假如在线程ta中调用tb.join()
操作,那么就是ta在tb执行完成后执行
方法介绍:
t.join()
允许t线程在当前线程之前执行,待t线程执行结束当前线程在执行(当前线程无限等待)t.join(long mills)
允许t线程在当前线程之前执行,且最长时间mills毫秒之后,当前线程在执行(当先线程有限等待)t.join(long millis, int nanos)
允许t线程在当前线程之前执行,且最长时间mills毫秒加上nanos纳秒之后,当前线程在执行(当先线程有限等待)
特点:
- join方法是Thread类中的方法,会抛出InterruptedException异常
- 线程状态:当前线程ta中tb.join,tb会执行,ta线程会进入Waiting或Timed_waiting状态
- 当前线程ta中tb.join,tb会执行,则ta线程会释放当前持有的锁,join方法是通过wait/notify的线程通信机制实现的,wait方法会释放锁
public class ThreadDemo2 extends Thread {
private Thread thread; //线程实例
private String name;//线程名
public ThreadDemo2(Thread thread, String name) {
this.thread = thread;
this.name = name;
}
@Override
public void run() {
if (thread != null) {
try {
thread.join(); //让当前类实例等待thread线程执行结束后在执行
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int i=1;i<=10;i++){
System.out.println(this.name +":"+i);
}
}
}
public static void main( String[] args ) {
//假如存在A、B、C三个线程,让三个线程按照A、B、C的顺序打印1~10
ThreadDemo2 A = new ThreadDemo2(null, "线程A");
ThreadDemo2 B = new ThreadDemo2(A, "线程B");
ThreadDemo2 C = new ThreadDemo2(A, "线程C");
c.start();//在虚拟机栈上维护一个start的帧栈 返回的地址
b.start();
a.start();
}
(5)interrupt()
public void interrupt()
:由线程对象调用,将java线程当中的中断状态位置为true
- 当thread A调用
sleep()/join()/wait()
方法后都会使得当前线程进入阻塞状态,而如果另外一个线程调用被阻塞线程的interrupt方法(例如:在thread B :中调用:thread A对象.interrupt()方法)会打断当前的这种阻塞状态,并抛出一个InterruptedException的异常,而且会消除中断状态位置标识,这样的方法称之为可中断方法。 - 需要注意的是,调用interrupt()方法并不是结束当前被阻塞线程的生命周期,只是打断了当前线程的阻塞状态。
public class TestDemo {
public static void main(String[] args) {
Thread thread = new Thread(){
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
System.out.println("I am be interrupted");
}
}
};
thread.start();
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
}
isInterrupted()
和interrupted()
:判断中断状态位是否位true。
- 区别在于
interrupted
方法调用之后会擦除掉线程的中断状态位置标识。
public class TestDemo {
public static void main(String[] args) {
Thread thread = new Thread() {
@Override
public void run() {
while (true) {
System.out.println(Thread.interrupted());
}
}
};
thread.setDaemon(true);
thread.start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
// System.out.println(thread.isInterrupted());
// thread.interrupt();
// System.out.println(thread.isInterrupted());
}
}
(6)Priority
Priority:线程的优先级
- 线程的优先级来指导线程的执行时的优先级
方法:
setPriority(int newPriority)
:设置优先级getPriority()
:获取当前线程的优先级值
特点:
- Java中线程的优先级并不绝对,它控制的是执行的机会,优先级高的线程有限执行的概率比较大,而优先级低的线程并不是没有机会,执行执行的概率相对低一点
- Java中的线程的优先级工10个优先级,分别为1-10,数值越大,表明优先级越高,一个普通的线程,其优先级为5,线程的优先级具有继承性。
线程优先级范围:
public final static int MIN_PRIORITY = 1; //最小优先级
public final static int NORM_PRIORITY = 5;//默认优先级
public final static int MAX_PRIORITY = 10;//最大优先级
(7)wait()/notify()/notifyAll()
-
首先这三个方法都是存在于Object类中的方法。
-
wait()
方法调用在synchronized同步代码块或方法当中,使得当前线程进入阻塞状态。 -
而
notify()/notifyAll()
方法能够唤醒当前线程的阻塞状态。
4、线程调度
-
用户级调度
通过调用相应的方法来改变线程状态从而达到线程的调度
1、调整线程的优先级,Java中线程具有优先级的,优先级高的线程获得较多的寄回去先执行
2、线程睡眠,Thread.sleep()
线程进入阻塞
3、线程等待,wait()
4、线程让步:yield()
5、线程合并:join()
-
系统级调度
指系统在特定的时机自动进行调度,主要涉及调度算法
FIFO
:先进先出算法
SJF(Shortest Job First)
:最短作业优先算法
RR(Round Robin)
:时间片轮转算法
HPF(Highest Priority First)
:最高优先级算法