JAVA多线程的初级认识1--线程的基本认识
-
为什么要有多线程?
从最开始的真空管穿孔打卡,到后来的晶体管批处理系统,再到后来的集成电路多核并行执行。从硬件资源的级别程度逐渐提高,但是软件如果对硬件资源利用率低,也是一种资源的损耗,所以随之而来的进程和线程应运而生。
为什么有了进程还需要出现线程?
先说一下进程的弊端。
- 相比进程,对于CPU时间片切换,线程是轻量级的。
- 仅有单线程无线程的话,如果单个IO阻塞了整个进程,那么程序就会Hang住,从而降低了资源利用率。
而线程是现在cpu执行的最小单位,众所周知,CPU是通过时间片切换来进行类似于并发的效果的。线程的上下文切换的量级远小于线程,从而可以更大程度的利用CPU资源。
-
JAVA的线程状态
其实学习线程状态最好是看看Thread类源码,里面有一个State的Enum类,写几个demo看看~现在截图一下看看Thread源码关于线程状态的注释:
public enum State { /** * 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; }
一共6种状态,具体的转换图如下:
查看线程状态可以使用JDK提供的工具来进行辅助~包括JPS,JSTACK。
JPS获取java进程号。
JSTACK可以获取线程堆栈的具体信息
-
线程的启动和销毁
线程的启动,不考虑Callable和Future的前提下,只考虑Thread和Runnable。我们看Thread的源码,我们都是通过调用Start方法而非run方法来启动线程的。
start方法查看进去,会调用一个start0的native方法。该方法我们就看不到了,因为是cpp源码,我们可以找到http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/00cd9dc3c2b5/src/share/native/java/lang/Thread.c 来看具体的Thread的源码~然后一步一步对应,通过start0-->jvm.cpp里面的JVM_Start_Thread-->thread.cpp里面的Thread.Java_thread和Start(需要下载hotspot源码)-->Thread.start里面会调用run方法
线程的销毁
Thread提供了stop和suspend方法,但是都已经过时,其实想想也很正确,A线程调用B线程的stop方法,本身就是一个很奇怪的事情。Thread提供了一个interrupt函数来优雅的中断一个线程。看源码又会走到c++源码中,具体细节不多讲了,结果能就是有一个volatile的interrupted的变量变成true,然后呢告知线程,有人向中断你,仅此而已,至于会不会被中断,是线程自己的事情。简单来说就是:
A想中断B线程,就调用B线程interrupt方法,然后B线程的interrupted boolean变量设置为true,B线程收到中断信号,如果不想处理,直接不理这个信号就好,然后调用Thread.interrupted方法来对interrupted变量进行复位。
Thread提供一种IsInterrupted方法来判断线程是否被中断。