线程状态
线程状态总共可分为五大状态: 新建 可运行 运行 等待阻塞睡眠 死亡,如下图所述:
1.新建(NEW): 线程对象已经创建,但还没调用start()方法。
2.可运行(RUNNABLE): 当线程有资格运行,但还没有获得cpu资源。当start()方法调用后,线程先处于可运行状态;当线程运行后或者从等待/阻塞/睡眠回来也可以进入可运行状态。
3.运行(RUNNING): 当一个可运行状态的线程获得cpu资源后被运行的状态。
4.阻塞(BLOCKED): 当一个处于运行态的线程出于某种原因暂时放弃了cpu的使用权从而进入阻塞态,直到线程进入可运行状态才有机会在此获得cpu使用权。
阻塞主要分为三种:
4.1 等待阻塞:正在执行的线程执行wait()方法后,jvm会将该线程放入等待队列(waiting queue)中.。
4.2 同步阻塞:正在运行的线程获取对象的同步锁时,该同步锁被其他线程占用,则jvm会把该线程放入锁池(lock pool)中。
4.3 其他阻塞:当正在运行的线程执行Thread.sleep()、或者执行join()方法、或者发出了IO请求时,jvm会把该线程置为阻塞状态,当sleep() 、join()终止时或者io请求结束后,该线程会再次进入可执行状态。
5.死亡: 当线程的run()方法执行完,或者异常退出时run()方法时,该线程的生命周期结束,死亡的线程不可以复生。
可以阻止线程运行的方式
1.睡眠
Thread.sleep(long mills)和Thread.sleep(long mills,int nanos)两个Thread类的静态方法可以强制当前正在运行的线程进入睡眠状态,苏醒之前不会进入可运行状态,当睡眠时间结束后再次进入可运行时间。
线程睡眠原因: 线程执行太快或者需要强制进入下一轮。
睡眠实现: 调用静态方法Thread.sleep()
睡眠的位置: 为了让其他线程有机会执行,可以将Thread.sleep()放在需要睡眠的线程的run方法里面;
/**
* @author FengTianHao
* @version 1.0
* @since 2018/11/15 17:04
*/
public class TestThread implements Runnable {
private String name;
public TestThread(String name) {
this.name = name;
}
@Override
public void run()
{
for(int i=0;i<100;i++)
{
System.out.println(name+i);
try {
Thread.sleep(30);//每到线程执行到这时会休眠30毫秒,给其他线程提供执行的机会
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args)
{
TestThread zhangsan=new TestThread("张三");
Thread t1=new Thread(zhangsan);
t1.start();
TestThread lisi=new TestThread("李四");
Thread t2=new Thread(lisi);
t2.start();
}
}
运行结果:
这样线程每次执行的过程中都会休眠30毫秒,其他的线程就有机会执行啦。关于线程创建的方式有不懂地方可以看看博主的创建线程的主要三种方式
注意:
(1). 线程睡眠是所有线程获得运行机会的最好方法。
(2). 当睡眠时间结束后线程进入可运行状态而不是运行状态,即sleep()方法不能保证线程睡眠结束后立即进入运行状态。
(3). sleep()是Thred类的静态方法,它只能控制当前正在运行的线程。
2.线程的优先级和线程让步yield()
线程的让步是通过Thread.yield()来实现的,yield()方法的作用:暂停当前正在运行的线程并执行其他的线程,被暂停的线程进入可执行状态。要理解yield()方法必须得先了解线程优先级的概念。线程存在优先级,范围:1~10;jvm调度线程总是基于优先级抢先调度机制。在大多数情况下,正在运行的线程优先级高于或者等于线程池的其他线程。但也是仅仅是大多数情况。
设置线程的优先级
线程创建好后会有一个默认优先级,可以通过setPriority(int newPriority)方法来设置新的优先级。优先级的高低代表着获得cpu的概率的高低,但是在现实中并没有多少用。
例如:
TestThread zhangsan=new TestThread("张三");
Thread t1=new Thread(zhangsan);
t1.setPriority(10);
线程默认的优先级是5,Thread类中有三个常量来表示优先级的范围
static int MAX_PRIORITY 10; 线程可以拥有的最高优先级
static int MIN_PRIORITY 1; 线程可以拥有的最低优先级
static int NORM_PRIORITY 5;线程的默认优先级
Thread.yield()方法
作用: 暂停正在运行的线程,运行其他的线程
调用yield()方法后,使得当前运行的线程进入可运行状态,然后允许优先权相等的其他线程获得运行的机会,因此,使用yield()方法可以使得有相同优先权的线程可以轮转执行;但现实中yield()方法并不可以保证线程让步,调用yield()方法的线程在下一轮可能又会被调度。
join()方法
join()方法是Thread类的一个非静态方法,它使一个线程a追加到一个线程b的尾部,在线程b执行完之前不可以执行。
例如:
TestThread zhangsan=new TestThread("张三");
Thread b=new Thread(zhangsan);
b.start();
TestThread lisi=new TestThread("李四");
Thread a=new Thread(lisi);
a.start();
如果没用用join(),这样的话线程a和线程b为并发执行
TestThread zhangsan=new TestThread("张三");
Thread b=new Thread(zhangsan);
b.start();
b.join();
TestThread lisi=new TestThread("李四");
Thread a=new Thread(lisi);
a.start();
使用join()后,这样的话线程a和线程b为同步执行,b先执行完后a开始执行
join()方法还可以使线程进入等待状态,例:
a.join(5000);
a线程进入等待状态并持续5000毫秒,等待结束后进入可执行状态
小结
使线程离开运行状态的方式有三种
- 调用Thread.sleep()可以使当前运行的线程睡眠多少毫秒。
- 调用Thread.yeild()使当前运行的线程回到可执行状态,除此之外不能保证什么。
- 调用join()方法可以当前线程停止执行直到加入的线程运行完为止。