线程从创建、运行到结束总是处于下面五个状态之一:新建状态、就绪状态、运行状态、阻塞状态及死亡状态。
![](https://img.haomeiwen.com/i19670917/572f9298d5efdabd.jpg)
新建状态(New)
当用new操作符创建一个线程时,例如new Thread(),线程还没有开始运行,此时线程处于新建状态。
就绪状态(Runnable)
线程对象被创建后,当线程对象调用start()方法,从而来启动该线程。处于就绪状态的线程,随时可能被CPU调度执行。
处于就绪状态的线程并不一定立即运行run()方法,线程还必须同其他线程竞争CPU时间,只有获得CPU时间才可以运行线程。因为在单CPU的计算机系统中,不可能同时运行多个线程,一个时刻仅有一个线程处于运行状态。因此此时可能有多个线程处于就绪状态。对多个处于就绪状态的线程是由Java运行时系统的线程调度程序(thread scheduler)来调度的。
运行状态(Running)
当线程获得CPU时间后,它才进入运行状态,真正开始执行run()方法。需要注意的是,线程只能从就绪状态进入到运行状态。
阻塞状态(Blocked)
所谓阻塞状态是正在运行的线程没有运行结束,暂时让出CPU,这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。
线程运行过程中,可能由于各种原因进入阻塞状态:
- 线程通过调用sleep方法进入睡眠状态;
- 线程试图得到一个锁,而该锁正被其他线程持有;
- 线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者;
- 线程在等待某个触发条件;
死亡状态(Dead)
run()方法执行结束,线程正常退出。
为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法。如果是可运行或被阻塞,这个方法返回true; 如果线程仍旧是new状态且不是可运行的, 或者线程死亡了,则返回false.
线程中经常用到的几个方法
Thread.sleep(long millis):一定是当前线程调用此方法,当前线程进入阻塞,但不释放对象锁,millis后线程自动苏醒进入可运行状态。作用:给其它线程执行机会的最佳方式。
Thread.yield():使当前线程从执行状态(运行状态)变为可执行态(就绪状态)。cpu会从众多的可执行态里选择,也就是说,当前也就是刚刚的那个线程还是有可能会被再次执行到的,并不是说一定会执行其他线程而该线程在下一次中不会执行到了。
public class ThreadTest {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " 执行 " + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (i == 3) {
System.out.println(Thread.currentThread().getName() + " 让出CPU ");
Thread.yield();
}
}
System.out.println(Thread.currentThread().getName() + " 执行结束 ");
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " 执行 " + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (i == 3) {
System.out.println(Thread.currentThread().getName() + " 让出CPU ");
Thread.yield();
}
}
System.out.println(Thread.currentThread().getName() + " 执行结束 ");
}
});
t1.setName("Thread-1");
t2.setName("Thread-2");
t1.start();
t2.start();
System.out.println(Thread.currentThread().getName() + " 执行结束 ");
}
}
运行结果![]()
t.join()/t.join(long millis):任何地方当调用了t.join(),就必须要等待线程t执行完毕后,才能继续执行其他线程。这里其实是运用了Java中最顶级对象Object提供的方法wait()。wait()方法用于线程间通信,它的含义是通知一个线程等待一下,让出CPU资源,注意这里是会放弃已经占有的资源的。直到t线程执行完毕,再调用notify()唤醒当前正在运行的线程。
public class ThreadTest {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " ");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " 执行结束 ");
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " ");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " 执行结束 ");
}
});
t1.setName("Thread-1");
t2.setName("Thread-2");
t1.start();
t1.join();
t2.start();
t2.join();
System.out.println(Thread.currentThread().getName() + " 执行结束 ");
}
运行结果![]()
obj.wait():当前线程调用对象的wait()方法,当前线程释放对象锁,进入等待队列。依靠notify()/notifyAll()唤醒或者wait(long timeout)timeout时间到自动唤醒。
obj.notify():唤醒正在等待对象监视器的单个线程,选择是任意性的。notifyAll()唤醒在此对象监视器上等待的所有线程。该方法不释放锁的。
public class ThreadDemo {
private volatile static List<String> list = new ArrayList<>(20);
public void add(int i) {
list.add("元素" +i);
}
public int size() {
return list.size();
}
public static void main(String[] args) {
final ThreadDemo wDemo = new ThreadDemo();
final Object obj = new Object();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
synchronized (obj) {
System.out.println("已进入t1");
for (int i = 0; i < 6; ++i) {
wDemo.add(i);
System.out.println("当前的线程:" + Thread.currentThread().getName() + "添加了一个元素。。");
Thread.sleep(200);
if (wDemo.size() == 5) {
obj.notify();
System.out.println("已发出通知!");
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (obj) {
System.out.println("已进入t2");
if (wDemo.size() != 5) {
try {
System.out.println("t2释放锁前");
obj.wait();
System.out.println("t2释放锁后");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t2线程收到通知");
}
}
}, "t2");
t2.start();
t1.start();
}
}
运行结果![]()
wait和notify必须配合synchronized使用,而且wait必须在notify前用,wait后就会进入notify所在的线程,notify后唤醒wait所在的线程,但是wait所在的线程仍然没有获取锁,需要等待notify所在的线程释放锁。
网友评论