Java Thread 的一些认识:
Java是抢占式线程,一个线程就是进程中单一的顺序控制流,单个进程可以拥有多个并发任务,其底层是切分CPU时间,多线程和多任务往往是使用多处理器系统的最合理方式
进程可以看作一个程序或者一个应用;线程是进程中执行的一个任务,多个线程可以共享资源
一个Java 应用从main 方法开始运行,main 运行在一个线程内,也被称为 “主线程”,Runnable也可以理解为Task (任务)
JVM启动后,会创建一些守护线程来进行自身的常规管理(垃圾回收,终结处理),以及一个运行main函数的主线程
随着硬件水平的提高,多线程能使系统的运行效率得到大幅度的提高,同时异步操作也增加复杂度和各种并发问题
■ 线程 VS 进程
在一个已有进程中创建一个新线程比创建一个新进程快的多
终止一个线程比终止一个进程快的多
同一个进程内线程间切换比进程间切换更快
线程提供了不同的执行程序间通信的效率,同一个进程中的线程共享同一进程内存和文件,无序调用内核就可以互相通信,而进程间通信必须通过内核
■ 同步和异步
同步方法一旦开始,调用者必须等到方法调用返回之后,才能继续后续行为
无先后顺序,一旦开始,方法调用便立即返回,调用者就可以继续后续行为,一般为另一个线程执行
■ 阻塞和非阻塞
当一个线程占用临界区资源,其他线程也想要使用该资源就必须等待,等待会导致线程的挂起,也就是阻塞(线程变成阻塞状态)。
此时若占用资源的线程一直不愿意释放资源,那么其他所有阻塞在该临界区的线程都会被挂起,变成阻塞状态,不能正常工作,直到占用线程释放资源
非阻塞强调没有一个线程可以妨碍其他线程执行,所有线程都会尝试去做下一步工作
■ 临界资源与临界区
一般指的是公共共享资源,即可以被多个线程共享使用。但同一时间只能由一个线程去访问和操作临界区的资源,一旦临界区资源被一个线程占用,其他线程也想要使用该资源就必须等待,
就好比好多人想上大号,但只有一个坑,一个人占了坑,其他人就得排队等待喽
临界区可以认为是一段代码,线程会在该端代码中访问共享资源,因此临界区的界定标准就是是否访问共享(临界)资源(有点类似形成闭包的概念);一次只允许有一个程序(进程/线程)在该临界区中
■ 类定义
public class Thread implements Runnable {
/* Make sure registerNatives is the first thing does.
初始化时调用 Java 本地方法,实现了Runnable接口
*/
private static native void registerNatives();
static {
registerNatives();
}
■ 构造器
/**
* 默认构造器
* 其中name规则为 "Thread-" + nextThreadNum()
*/
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
/**
* 创建一个指定Runnable的线程
* 其中name规则为 "Thread-" + nextThreadNum()
*/
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
/**
* 创建一个指定所属线程组和Runnable的线程
* 其中name规则为 "Thread-" + nextThreadNum()
*/
public Thread(ThreadGroup group, Runnable target) {
init(group, target, "Thread-" + nextThreadNum(), 0);
}
/**
* 创建一个指定name线程
*/
public Thread(String name) {
init(null, null, name, 0);
}
/**
* 创建一个指定所属线程组和name的线程
*/
public Thread(ThreadGroup group, String name) {
init(group, null, name, 0);
}
/**
* 创建一个指定Runnable和name的线程
*/
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
/**
* Allocates a new {@code Thread} object so that it has {@code target}
* as its run object, has the specified {@code name} as its name,
* and belongs to the thread group referred to by {@code group}.
* 创建一个新的Thread对象,同时满足以下条件:
* 1.该线程拥有一个指定的Runnable对象用于方法执行
* 2.该线程具有一个指定的名称
* 3.该线程属于一个指定的线程组ThreadGroup
*
If there is a security manager, its
* {@link SecurityManager#checkAccess(ThreadGroup) checkAccess}
* method is invoked with the ThreadGroup as its argument.
* 若这里有个安全管理器,则ThreadGroup将调用checkAccess方法进而触发SecurityManager的checkAccess方法
*
In addition, its {@code checkPermission} method is invoked with
* the {@code RuntimePermission("enableContextClassLoaderOverride")}
* permission when invoked directly or indirectly by the constructor of a subclass which
* overrides the {@code getContextClassLoader} or {@code setContextClassLoader} methods.
* 当enableContextClassLoaderOverride被开启时,checkPermission将被重写子类直接或间接地调用
*
The priority of the newly created thread is set equal to the
* priority of the thread creating it, that is, the currently running
* thread. The method {@linkplain #setPriority setPriority} may be
* used to change the priority to a new value.
* 新创建的Thread的优先级等同于创建它的线程的优先级,调用setPriority会变更其优先级
*
The newly created thread is initially marked as being a daemon
* thread if and only if the thread creating it is currently marked
* as a daemon thread. The method {@linkplain #setDaemon setDaemon}
* may be used to change whether or not a thread is a daemon.
* 当且仅当线程创建时被显示地标记为守护线程,新创建的线程才会被初始化为一个守护线程
* setDaemon方法可以设置当前线程是否为守护线程
*/
public Thread(ThreadGroup group, Runnable target, String name) {
init(group, target, name, 0);
}
/**
* Allocates a new {@code Thread} object so that it has {@code target} as its run object,
* has the specified {@code name} as its name, and belongs to the thread group referred to
* by {@code group}, and has the specified stack size.
* 创建一个新的Thread对象,同时满足以下条件:
* 1.该线程拥有一个指定的Runnable对象用于方法执行
* 2.该线程具有一个指定的名称
* 3.该线程属于一个指定的线程组ThreadGroup
* 4.该线程拥有一个指定的栈容量
*
This constructor is identical to {@link #Thread(ThreadGroup,Runnable,String)}
* with the exception of the fact that it allows the thread stack size to be specified.
* The stack size is the approximate number of bytes of address space that the virtual machine
* is to allocate for this thread's stack. The effect of the {@code stackSize} parameter,
* if any, is highly platform dependent.
* 栈容量指的是JVM分配给该线程的栈的地址(内存)空间大小,这个参数的效果高度依赖于JVM运行平台
*
On some platforms, specifying a higher value for the {@code stackSize} parameter may allow
* a thread to achieve greater recursion depth before throwing a {@link StackOverflowError}.
* Similar