JDK1.8 Thread类说明
Posted zhujm320
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK1.8 Thread类说明相关的知识,希望对你有一定的参考价值。
简介
Thread Java线程类,用于线程相关操作,是并发和多线程的基础。本文将对Thread源码和日常使用的函数进行解读。在对线程的使用有基本的了解后,再来阅读它的源码,有助于加深对线程的理解;如有小伙伴对线程的使用不是很清楚的话,请参考《Java开启线程的4种方式》。
线程是操作系统中的概念,也是系统调度的基本单元。对于线程的创建,通常通过系统的API来进行创建,Thread的线程创建也是通过系统API来进行创建,Thread只是对系统线程的一个包装。
构造函数
初始化线程
private void init(ThreadGroup g, Runnable target, String name,
long stackSize)
init(g, target, name, stackSize, null, true);
参数说明
参数 | 说明 |
---|---|
ThreadGroup g | 线程组 |
Runnable target | 线程启动后,线程中回调run的目标对象 |
String name | 线程名 |
long stackSize | 线程栈大小 |
调用6参得初始化线程函数
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals)
参数说明
参数 | 说明 |
---|---|
ThreadGroup g | 线程组 |
Runnable target | 线程回调run方法 |
String name | 线程名字 |
long stackSize | 线程堆栈大小 |
AccessControlContext acc | 上下文 |
boolean inheritThreadLocals | 是否继承ThreadLocals的值 |
无参构造函数
public Thread()
init(null, null, "Thread-" + nextThreadNum(), 0);
带一个参数构造函数
public Thread(Runnable target)
init(null, target, "Thread-" + nextThreadNum(), 0);
参数 | 说明 |
---|---|
Runnable target | 线程回调后的目标对象 |
public Thread(String name)
init(null, null, name, 0);
参数 | 说明 |
---|---|
String name | 线程名 |
带两个参数的构造函数
Thread(Runnable target, AccessControlContext acc)
init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
参数 | 说明 |
---|---|
Runnable target | 线程回调后的目标对象 |
AccessControlContext acc | 系统资源访问决策类 |
public Thread(ThreadGroup group, Runnable target)
init(group, target, "Thread-" + nextThreadNum(), 0);
参数 | 说明 |
---|---|
ThreadGroup group | 线程组 |
Runnable target | 线程回调后的目标对象 |
public Thread(ThreadGroup group, String name)
init(group, null, name, 0);
参数 | 说明 |
---|---|
ThreadGroup group | 线程组 |
String name | 线程名 |
带三个参数的构造函数
public Thread(ThreadGroup group, Runnable target, String name)
init(group, target, name, 0);
参数 | 说明 |
---|---|
ThreadGroup group | 线程组 |
Runnable target | 线程回调后的目标对象 |
String name | 线程名 |
带四个参数的构造函数
public Thread(ThreadGroup group, Runnable target, String name,
long stackSize)
init(group, target, name, stackSize);
参数 | 说明 |
---|---|
ThreadGroup group | 线程组 |
Runnable target | 线程回调后的目标对象 |
String name | 线程名 |
long stackSize | 线程堆栈大小 |
从以上看,Thread构造函数都是通过调用init函数进行初始化。
线程启动函数
通过调用Thread类的start()函数,线程正式启动,并且会调用run方法,此时run方法就是在线程中执行。
public synchronized void start()
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try
start0();
started = true;
finally
try
if (!started)
group.threadStartFailed(this);
catch (Throwable ignore)
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
private native void start0();
start方法只能调用一次,多次调用会包异常,start方法通过jni方法start0启动线程,由于Thread类只是对系统线程的一个封装,通过start0启动系统线程,启动线程启动后,通过jni回调run方法。
线程运行run方法
@Override
public void run()
if (target != null)
target.run();
线程真正运行的地方,系统线程启动后,回调run方法,所以说在start后,run方法是在线程中执行。
Native方法
//获取当前运行线程对象
public static native Thread currentThread();
//线程礼让, 让出自己的cpu,让别人执行
public static native void yield();
//线程休眠 单位毫秒
public static native void sleep(long millis) throws InterruptedException;
//线程启动的真正方法
private native void start0();
//线程是否活着
public final native boolean isAlive();
//设置线程优先级
private native void setPriority0(int newPriority);
//停止线程
private native void stop0(Object o);
//暂停线程
private native void suspend0();
//唤醒线程
private native void resume0();
//中断线程
private native void interrupt0();
//设置线程名字
private native void setNativeName(String name);
线程退出
private void exit()
if (group != null)
group.threadTerminated(this);
group = null;
/* Aggressively null out all reference fields: see bug 4006245 */
target = null;
/* Speed the release of some of these resources */
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
线程退出函数,调用该函数后,线程不一定会真正退出,如果在run方法中执行如下代码:
public void run()
while(true)
....
这样线程就无法退出了
线程中断通知
public void interrupt()
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock)
Interruptible b = blocker;
if (b != null)
interrupt0(); // Just to set the interrupt flag
b.interrupt(this);
return;
interrupt0();
给真正运行的线程发送中断通知,以便该线程在执行时,能够收到该中断
public void run()
while(true)
try
...
catch(Exception e)
...
在run方法中进行异常捕获,当线程发起中断通知时,以便在线程中能收到。如果在run方法中没有去捕获异常的话,那么即使调用interrupt(),线程也是无法得到中断通知。
public static boolean interrupted()
return currentThread().isInterrupted(true);
测试该线程是否已经进行中断,重置当前线程的中断状态。
public boolean isInterrupted()
return isInterrupted(false);
判断该线程是否中断,不会清楚线程中断状态
设置线程优先级
public final void setPriority(int newPriority)
ThreadGroup g;
checkAccess();
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY)
throw new IllegalArgumentException();
if((g = getThreadGroup()) != null)
if (newPriority > g.getMaxPriority())
newPriority = g.getMaxPriority();
setPriority0(priority = newPriority);
线程优先级从小到大分为1-10个等级,默认优先级为5
获取线程优先级
public final int getPriority()
return priority;
设置线程名字
public final synchronized void setName(String name)
checkAccess();
if (name == null)
throw new NullPointerException("name cannot be null");
this.name = name;
if (threadStatus != 0)
setNativeName(name);
给线程设置一个名字
获取线程名字
public final String getName()
return name;
join方法(停止当前线程执行另外一个线程,另外一个线程结束后再执行本线程)
public final synchronized void join(long millis)
throws InterruptedException
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0)
throw new IllegalArgumentException("timeout value is negative");
if (millis == 0)
while (isAlive())
wait(0);
else
while (isAlive())
long delay = millis - now;
if (delay <= 0)
break;
wait(delay);
now = System.currentTimeMillis() - base;
/**
* Waits at most @code millis milliseconds plus
* @code nanos nanoseconds for this thread to die.
*
* <p> This implementation uses a loop of @code this.wait calls
* conditioned on @code this.isAlive. As a thread terminates the
* @code this.notifyAll method is invoked. It is recommended that
* applications not use @code wait, @code notify, or
* @code notifyAll on @code Thread instances.
*
* @param millis
* the time to wait in milliseconds
*
* @param nanos
* @code 0-999999 additional nanoseconds to wait
*
* @throws IllegalArgumentException
* if the value of @code millis is negative, or the value
* of @code nanos is not in the range @code 0-999999
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public final synchronized void join(long millis, int nanos)
throws InterruptedException
if (millis < 0)
throw new IllegalArgumentException("timeout value is negative");
if (nanos < 0 || nanos > 999999)
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
if (nanos >= 500000 || (nanos != 0 && millis == 0))
millis++;
join(millis);
/**
* Waits for this thread to die.
*
* <p> An invocation of this method behaves in exactly the same
* way as the invocation
*
* <blockquote>
* @linkplain #join(long) join@code (0)
* </blockquote>
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public final void join() throws InterruptedException
join(0);
执行流程图如下:
join方法中,有下面这段
public final synchronized void join(long millis)
throws InterruptedException
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0)
throw new IllegalArgumentException("timeout value is negative");
if (millis == 0)
while (isAlive()) //判断线程是否活着
wait(0); //调用者线程等待
else
while (isAlive())
long delay = millis - now;
if (delay <= 0)
break;
wait(delay);
now = System.currentTimeMillis() - base;
也就是说在哪一个线程中调用了join方法,那么它就等待,直到join对象的那个线程退出,例子如下:
public static void main(String[] args)
Thread t1 = new Thread(()->
System.out.println("t1 start...");
Thread t2 = new Thread(()->
System.out.println("t2 start...");
try
Thread.sleep(2000);
catch (Exception e)
e.printStackTrace();
System.out.println("t2 end...");
);
t2.start();
try
t2.join();
catch (InterruptedException e)
e.printStackTrace();
System.out.println("t1 end...");
);
t1.start();
执行结果:
t1 start...
t2 start...
t2 end...
t1 end...
在线程t1中启动线程t2,然后调用t2.join方法,那么t2.join是在t1线程中执行的,t1将阻塞直到t2运行结束。
获取类加载器
public ClassLoader getContextClassLoader()
if (contextClassLoader == null)
return null;
SecurityManager sm = System.getSecurityManager();
if (sm != null)
ClassLoader.checkClassLoaderPermission(contextClassLoader,
Reflection.getCallerClass());
return contextClassLoader;
类加载器用来加载一些class文件
设置类加载器
public void setContextClassLoader(ClassLoader cl)
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkPermission(new RuntimePermission("setContextClassLoader"));
contextClassLoader = cl;
获取线程ID
public long getId()
return tid;
线程状态
public enum State
/**
* NEW状态: 并没有调用start方法
*/
NEW,
/**
* 可执行状态: 调用start方法
*/
RUNNABLE,
/**
* 阻塞状态,在run中调用了wait或者synchronized方法导致了阻塞
*/
BLOCKED,
/**
* 等待状态: 调用Object.wait()后的状态
*/
WAITING,
/**
* 等待超时状态: 调用Object.wait(timeOut), timeOut结束后的状态
*/
TIMED_WAITING,
/**
* 结束状态: 线程结束状态
*/
TERMINATED;
状态切换图:
以上是关于JDK1.8 Thread类说明的主要内容,如果未能解决你的问题,请参考以下文章