线程定义
线程是现代操作系统调度的最小单元,一个进程可以创建多个线程来提高系统的吞吐量和执行效率。
注:进程是操作系统资源分配和调度的基本单位,它可以创建多个线程,进程可创建的线程数量跟操作系统相关。
为什么要使用多线程?
- 更多的处理器核心;
- 更快的响应时间;
- 更好的编程模型:java提供了一套完整的jmm规则,屏蔽了底层的一些操作,开发人员只需要关注自己的业务逻辑即可。
线程的状态
- NEW:初始状态,线程被构建,还未调用start()方法;
- RUNNABLE:运行状态,在java多线程模型中,就绪和运行都是运行状态;
- BLOCKED:阻塞状态;
- WAITING:等待状态,比如中断,需要其他的线程来唤醒;
- TIME_WAITING:超时等待,可以在指定的时间内自行返回;
- TERMINATED:终止状态,线程执行完毕。
Thread源码分析
- 构造线程
构造函数:
//无参构造方法
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
//带参构造方法
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
public Thread(ThreadGroup group, Runnable target) {
init(group, target, "Thread-" + nextThreadNum(), 0);
}
public Thread(String name) {
init(null, null, name, 0);
}
public Thread(ThreadGroup group, String name) {
init(group, null, name, 0);
}
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
public Thread(ThreadGroup group, Runnable target, String name) {
init(group, target, name, 0);
}
public Thread(ThreadGroup group, Runnable target, String name, long stackSize) {
init(group, target, name, stackSize);
}
所有的构造方法都调用了init这个方法,接下来我们就来详细的看看init方法到底是怎么来初始化线程的。
初始化线程:
private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc) {
//参数校验,线程name不能为null
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name.toCharArray();
//当前线程就是该线程的父线程
Thread parent = currentThread();
//获取系统的security
SecurityManager security = System.getSecurityManager();
if (g == null) {
//security不为null时,线程所在group为security的group
if (security != null) {
g = security.getThreadGroup();
}
//security为null时,直接使用父线程的group
if (g == null) {
g = parent.getThreadGroup();
}
}
g.checkAccess();
//授权
if (security != null) {
if (isCCLOverridden(getClass())) { security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
g.addUnstarted();
this.group = g;
//将守护线程、优先级等设置为父线程的对应属性
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
this.target = target;
setPriority(priority);
if (parent.inheritableThreadLocals != null)
//创建线程共享变量副本
this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
this.stackSize = stackSize;
//分配线程id
tid = nextThreadID();
}
- 启动线程
public synchronized void start() {
//假若当前线程初始化还未做好,不能start,0->NEW状态
if (threadStatus != 0)
throw new IllegalThreadStateException();
//通知group该线程即将启动,group的未启动线程数量减1
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
//启动不成功,group设置当前线程启动失败
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
启动线程其实做了这么几件事:
- 检查线程是否初始化;
- 通知group,线程启动;
- 调用native方法start0()启动线程,启动后执行run()方法;
- 启动失败容错处理。
- 线程中断
中断可以理解为一个标识位的属性,它标识一个运行中的线程是否被其他线程进行了中断操作。
中断线程:
public void interrupt() {
//中断其他线程,需要先判断当前线程是否允许修改其他线程
if (this != Thread.currentThread())
checkAccess();
//中断该线程
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0();//设置中断标识位
b.interrupt(this);
return;
}
}
interrupt0();
}
查看当前线程是否被中断:
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
查看线程是否被中断,已中断返回false
public boolean isInterrupted() {
return isInterrupted(false);
}
- 线程的暂停、恢复和停止
注: 这几个操作都加有@Deprecated注解,不推荐程序员使用
暂停:
//可能会造成死锁
@Deprecated
public final void suspend() {
checkAccess();
suspend0();
}
恢复:
//可能会造成死锁
@Deprecated
public final void resume() {
checkAccess();
resume0();
}
停止:
@Deprecated
public final synchronized void stop(Throwable obj) {
if (obj == null)
throw new NullPointerException();
SecurityManager security = System.getSecurityManager();
if (security != null) {
checkAccess();
if ((this != Thread.currentThread()) ||
(!(obj instanceof ThreadDeath))) {
security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
}
}
//线程还未初始化好,暂停该线程
if (threadStatus != 0) {
resume();
}
//jvm处理线程相关内容
stop0(obj);
}
- 线程优先级设置
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);
}
}
需要注意的是:线程优先级不能作为程序正确性的依赖,操作系统有线程优先级的设定,不以程序设定的优先级为准!