一、线程生命周期
在《详解操作系统进程》中,从操作系统层面介绍了进程(线程)的生命周期的变迁,在操作系统中,线程的状态主要包含了五种:初始化、等待状态、就绪状态、运行状态和终止状态
但在Java中,定义了六种状态的,其中RUNNABLE状态对应运行状态和就绪状态,而等待状态在Java中细分为三种BLOCKED、WAITING、TIMED_WAITING
关于这三种状态的描述,下面的源码中的注释已经解释的很清楚
BLOCKED状态对应于对象锁,某个线程竞争对象锁失败时就处于阻塞状态
WAITING状态对应于永久等待,如果没有被唤醒,将会处于永久等待的状态
TIMED_WAITING状态对应于超时等待,超过了等待的时间之后,它们就会被主动唤醒,然后处于RUNNABLE状态,等待CPU分配时间片
public enum State {
NEW,
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,
/**
* <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>
*/
WAITING,
/**
* <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,
TERMINATED;
}
Java中这六种线程状态的生命周期,可以用下面的图来表示:
);
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(“wait end …….”);
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(“wait end ……. “);
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
if (flag){
synchronized (lock){
if (flag){
lock.notify();
System.out.println(“notify …….”);
flag = false;
}
}
}
}
}).start();
}
}
注:wait于notify()必须结合synchronized关键字使用,否则会抛出IllegalMonitorStateException
异常
等待唤醒机制的另一种实现是LockSupport,LockSupport是JDK中用来实现线程阻塞和唤醒的工具,线程调用park()方法则等待”许可“,调用unpark()方法则为指定线程提供”许可“。使用LockSupport的好处是,可以在任何场景使线程阻塞(不需要像wait()方法需要结合synchronized关键),并且不用担心阻塞和唤醒的顺序,但是要注意多次唤醒的效果和一次唤醒的效果一样
public class LockSupportTest {
public static void main(String[] args) {
Thread parkThread = new Thread(new ParkThread());
parkThread.start();
System.out.println("唤醒parkThread");
LockSupport.unpark(parkThread);
}
static class ParkThread implements Runnable{
@Override
public void run() {
System.out.println("ParkThread开始执行");
LockSupport.park();
System.out.println("ParkThread执行完成");
}
}
}
4.3 管道输入输出流
管道输入/输出流和普通文件输入/输出流或者网络输入/输出流的不同指出在于,它主要用于线程之间的数据传输,而传输的媒介为内存。管道输入/输出流主要包括如下四种具体实现:
PipedOutputStream、PipedInputStream、PipedReader和PipedWriter,前面两种面向字节,而后面两种面向字符
public class PipedTest {
public static void main(String[] args) throws Exception {
PipedWriter out = new PipedWriter();
PipedReader in = new PipedReader();
// 将输出流和输入流进行连接,否则在使用时会抛出IOException
out.connect(in);
Thread printThread = new Thread(new Print(in), "PrintThread");
printThread.start();
int receive = 0;
try {
while ((receive = System.in.read()) != -1) {
out.write(receive);
}
} finally {
out.close();
}
}
static class Print implements Runnable {
private PipedReader in;
public Print(PipedReader in) {
this.in = in;
}
@Override
public void run() {
int receive = 0;
try {
while ((receive = in.read()) != -1) {
System.out.print((char) receive);
}
} catch (IOException ex) {
}
}
}
}
4.4 Thread.join()
join()方法可以理解为线程合并,将并行的线程通过join()方法合并成串行的,因为当前线程会一直阻塞等待调用join()方法的线程执行完毕才能继续执行(如果没有指定时间),所以join()方法的好处是可以保证线程的执行顺序,但是如果调用线程的join()方法其实已经失去了并行的意义,虽然存在多个线程,但这些线程本质上还是串行的。join()的实现也是基于等待唤醒机制的。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/112130.html