线程状态
java的线程一共有五种状态,分别为new(新建), runnable(就绪),running(执行),blocked(阻塞),dead(死亡)
new
新建状态:当我们new Thread()完一个线程之后,它就处于新建状态了。
runnable
就绪状态:当我们start()一个线程的时候,他就处于一个就绪状态,然后等待cpu的时间片。
running
运行状态:当就绪状态的线程分配到了cpu时间片(执行线程的代码)的时候,他就处于运行状态。
blocked
BLOCKED : 阻塞状态,当线程竞争锁失败的时候会处于这种状态
//t1,t2锁同一个对象,t1启动后t2才启动,保证t1的run代码在t2之前先执行,t1执行后休眠1000s,线程休眠不释放锁,保证t2一定处于阻塞状态,我们用jvisualvm查看线程状态
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (a){
System.out.println("--->"+ Thread.currentThread().getName());
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (a){
System.out.println("--->"+ Thread.currentThread().getName());
}
}
});
t1.start();
Thread.sleep(1000);
t2.start();
Thread.sleep(100000);
"Thread-0" #13 prio=5 os_prio=0 tid=0x000000001d7e2000 nid=0x4300 waiting on condition [0x000000001e58f000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
"Thread-1" #14 prio=5 os_prio=0 tid=0x000000001d7ce800 nid=0x11b4 waiting for monitor entry [0x000000001e68f000]
java.lang.Thread.State: BLOCKED (on object monitor)
t1对应Thread-0;t2对应Thread-1,t1处于timed_watting状态,t2处于blocked状态,是因为他因为竞争不到锁.
TIMED_WAITING: 等待一段时间;当调用wait(time),Thread.sleep(time),线程会处于这种状态
上面的例子中t1之所以TIMED_WAITTING,是因为t1执行了Thread.sleep(int time)的方法,实际上wait(int time)也会使线程处于这种状态.
WAITING : 等待状态,当调用wait()方法的时候会处于这种状态
dead
死亡状态,当线程执行完毕处于这种状态
wait()/notify()/notifyAll()
wait()/notify()/notifyAll()这三个都是object的内置方法,他只能在监视器(synchronized)内使用,作用的是该监视器相关的线程.当他们运行在监视器外面的时候会报错.
该图是Java的监视器结构图(synchronized实际就是通过监视器来实现同步的),它由三部分组成,owner是存储的是正在执行的线程(最多只有一个),waitSet是被wait()而正在等待的线程,entryList是竞争锁失败而等待的线程
wait()
当线程被wait()以后会进入waitSet等待队列中
notify()
唤醒waitSet中的一个线程
notifyAll()
唤醒waitSet的所有线程去竞争锁
sleep/yield/join
sleep/yield/join 都是Thread的静态方法,他们作用的是本线程
sleep
让线程休眠,但是休眠期间不释放锁.
yield
暂停带线程,将Running状态转变为Runnable状态
join
把本来的异步的线程加入到父线程中,父线程只有等该子线程执行完毕才能继续执行.
System.out.println(Thread.currentThread().getName() + ",start...");
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + ",start...");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + ",end...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
t.join();
System.out.println(Thread.currentThread().getName() + ",end...");
上面的例子中,假如没有t.join(),"main,end..."肯定在"Thread-0,end..."之前,因为Thread-0线程要休眠一分钟;但是如果加了t.join()之后,,"main,end..."在"Thread-0,end..."之后才输出,这是因为join的作用就是让子线程全部执行完才能执行父线程