相关博客:
构造 Thread 类
先看这么一段代码:
package com.example.threaddesign;
/**
* @author Dongguabai
* @date 2018/12/2 20:58
*/
public class ThreadTest {
public static void main(String[] args) {
Thread t = new Thread();
}
}
这里定义了一个 Thread 实例 t,目前 t 是处于 NEW 状态(并发编程学习之线程的生命周期(状态))。当前程序中只有一个线程,就是 main 线程。main 线程是 JVM 去创建的,而 Thread 只有在 start() 的时候才会产生。
Thread 的构造方法如下:
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
看看这个 init() 方法:
/**
* Initializes a Thread with the current AccessControlContext.
* @see #init(ThreadGroup,Runnable,String,long,AccessControlContext)
*/
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null);
}
这个方法有 4 个参数,第一个参数是选择 ThreadGroup;第二个参数可以看成是策略接口;第三个参数是线程的名称;最后一个参数是栈的大小。
而这个 init() 方法又调用了另外一个重载的 init() 方法:
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
...
最后一个参数 AccessControlContext 是与 JVM 权限有关,这里不用管。
线程名称
从这个方法的第一行代码可以看出,名称是不能为 null 的,那么 Thread 的命名规则是怎么样的呢,这里先测试一下:
运行结果:
那再创建一个 Thread,命名是怎样的呢?
运行结果:
回到 Thread 的无参构造函数:
查看 nextThreadNum() 方法:
/* For autonumbering anonymous threads. */
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
这个方法就很好理解了。这里的加锁还是 static 级别的。
也就是说创建一个 Thread,默认线程名是 Thread-0。我们也可以传入 Thread 的名称(具体可参看:创建线程时候声明线程名称)
target 参数
再看 Runnable target 参数。
在 init() 方法中可以看到:
...
this.target = target;
...
也就是说这里没有默认值了,传过来是 null 就是 null。start() 方法最终会执行它的 run() 方法:
/**
* If this thread was constructed using a separate
* <code>Runnable</code> run object, then that
* <code>Runnable</code> object's <code>run</code> method is called;
* otherwise, this method does nothing and returns.
* <p>
* Subclasses of <code>Thread</code> should override this method.
*
* @see #start()
* @see #stop()
* @see #Thread(ThreadGroup, Runnable, String)
*/
@Override
public void run() {
if (target != null) {
target.run();
}
}
如果构造传入 Runnable,就执行 Runnable 的 run() 方法,否则就需要重写 Thread 的 run() 方法,如果没有重写就啥也不做。
ThreadGroup 参数
在 init() 方法中:
/**
* Initializes a Thread with the current AccessControlContext.
* @see #init(ThreadGroup,Runnable,String,long,AccessControlContext)
*/
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null);
}
接着看重载的 init() 方法:
如果 g 为 null 就会走上面那一段逻辑,那个 security 先不管。而这个 parent 就是当前线程。也就是说如果构造线程对象时未传入 ThreadGroup,Thread 会默认获取父线程的 ThreadGroup 作为该线程的 ThreadGroup,此时子线程和父线程在同一个 ThreadGroup 中。
public static void main(String[] args) {
Thread t = new Thread();
t.start();
System.out.println(t.getThreadGroup().getName()); //main
System.out.println(Thread.currentThread().getName()); //main
System.out.println(Thread.currentThread().getThreadGroup().getName()); //main
}
ThreadGroup 中还有一些其它的 API,这里可以看看:
package com.example.threaddesign;
import java.util.Arrays;
/**
* @author Dongguabai
* @date 2018/12/2 20:58
*/
public class ThreadTest {
public static void main(String[] args) {
Thread t = new Thread(()->{
//保证 t 存活
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t.start();
//获取当前线程线程组
ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
//获取当前线程组中的活跃的线程数量
int activeCount = threadGroup.activeCount();
System.out.println(activeCount);
Thread[] arr = new Thread[activeCount];
//将当前线程组中的线程赋值至数组中
threadGroup.enumerate(arr);
Arrays.asList(arr).forEach(System.out::println);
System.in.read();
}
}
猜想的话当前活跃线程应该有两个,一个是 main 线程,一个是 t 线程。
输出结果:
发现还有一个 Monitor 线程,用来监听一些事件。
也能够看出 Monitor 线程是一个守护线程:
C:\Users\Dongguabai>jps
4496
15284 Launcher
2964 Launcher
4420 ThreadTest
9736 Jps
C:\Users\Dongguabai>jps -l
4496
15284 org.jetbrains.jps.cmdline.Launcher
2116 sun.tools.jps.Jps
2964 org.jetbrains.jps.cmdline.Launcher
4420 com.example.threaddesign.ThreadTest
C:\Users\Dongguabai>jstack --help
Usage:
jstack [-l] <pid>
(to connect to running process)
jstack -F [-m] [-l] <pid>
(to connect to a hung process)
jstack [-m] [-l] <executable> <core>
(to connect to a core file)
jstack [-m] [-l] [server_id@]<remote server IP or hostname>
(to connect to a remote debug server)
Options:
-F to force a thread dump. Use when jstack <pid> does not respond (process is hung)
-m to print both java and native frames (mixed mode)
-l long listing. Prints additional information about locks
-h or -help to print this help message
C:\Users\Dongguabai>jstack -l 4420
2018-12-03 18:45:40
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.65-b01 mixed mode):
"Service Thread" #10 daemon prio=9 os_prio=0 tid=0x0000000019ab1800 nid=0x11a8 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C1 CompilerThread2" #9 daemon prio=9 os_prio=2 tid=0x00000000199dc000 nid=0x418 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C2 CompilerThread1" #8 daemon prio=9 os_prio=2 tid=0x00000000199db000 nid=0x25c8 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C2 CompilerThread0" #7 daemon prio=9 os_prio=2 tid=0x00000000199da000 nid=0x26ac waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0 tid=0x0000000019976000 nid=0x417c runnable [0x0000000019efe000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:170)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
- locked <0x00000000d6259a10> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
- locked <0x00000000d6259a10> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64)
Locked ownable synchronizers:
- None
"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x00000000184ad000 nid=0x15fc waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x0000000019843800 nid=0x2e4 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x0000000003969000 nid=0x40d4 in Object.wait() [0x00000000197ff000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d5f870b8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
- locked <0x00000000d5f870b8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)
Locked ownable synchronizers:
- None
"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x0000000018459000 nid=0x26d4 in Object.wait() [0x00000000196ff000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d5f86af8> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:157)
- locked <0x00000000d5f86af8> (a java.lang.ref.Reference$Lock)
Locked ownable synchronizers:
- None
"main" #1 prio=5 os_prio=0 tid=0x0000000003874000 nid=0x1124 runnable [0x000000000327f000]
java.lang.Thread.State: RUNNABLE
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:255)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
- locked <0x00000000d5fdca10> (a java.io.BufferedInputStream)
at com.example.threaddesign.ThreadTest.main(ThreadTest.java:32)
Locked ownable synchronizers:
- None
"VM Thread" os_prio=2 tid=0x0000000018458000 nid=0x3514 runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000003889800 nid=0x4220 runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x000000000388b000 nid=0xac0 runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x000000000388c800 nid=0x2e10 runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x000000000388e000 nid=0x1520 runnable
"VM Periodic Task Thread" os_prio=2 tid=0x0000000019ae1000 nid=0x37b4 waiting on condition
JNI global references: 341