多线程学习笔记
在之前的java
开发中一般都是java web
方向的工作,对多线程使用的非常少。了解仅限于Runnable
和Thread
的区别与使用。最近在做小工具的时候用到了多线程,从零开始学习关于多线程和并发方面的知识。
并发和多线程之间的关系
并发与多线程之间的关系就是目的与手段之间的关系。并发(Concurrent)的反面是串行。并发的极致就是并行(Parallel)。多线程就是将原本可能是串行的计算“改为”并发(并行)的一种手段、途径或者模型。因此,有时我们也称多线程编程为并发编程。当然,目的与手段之间常常是一对多的关系。并发编程还有其他的实现途径,多线程编程往往是其他并发编程模型的基础。
实现多线程的方式:1.继承Thread
类,2.实现Runnable
接口。实际上Thread
也是Runnable
的一个子类。使用继承Thread
最大的局限性在于不支持多继承。所以为了支持多继承,就会使用Runnable
接口的方式。
Runnable
接口就是定义了一个run
方法。所以重点看Thread
类。
Thread
有9个构造方法。常用的有Thread()
和Thread(Runnable)
两个,构造方法都调用了init()
方法,初始化一个线程。
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name.toCharArray();
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* 判断是否为 applet */
/* 如果有security manager */
if (security != null) {
g = security.getThreadGroup();
}
/* 如果 security manager getThreadGroup 为null*/
if (g == null) {
g = parent.getThreadGroup();
}
}
/* 不管是否是传入参数的ThreadGroup 都再进行security manager 检查*/
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);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
}
通过init(ThreadGroup, Runnable, String, stackSize, AccessControlContext)
方法来完成Thread
对象的创建 整个过程是
-
registerNatives()
静态块, 判断name
。设置name
,获取Thread parent
,获取SecurityManager
。 - 检查
security
.线程组中的nUnstartedThreads++
。 - 设置
ThreadGroup
线程组,设置daemon
是否守护线程,priority
优先,ContextClassLoader
classLoader,inheritedAccessControlContext
继承的访问控制上下文,target
为继承Runnable
接口的对象。inheritableThreadLocals
threadLocal,stackSize
,id
设置。
整个Thread
对象的创建过程大概就是这样一个流程。