0
点赞
收藏
分享

微信扫一扫

Thread 类中的几个细节(一)

雪域迷影 2022-12-22 阅读 105


相关博客:

​​Thread 类中的几个细节(二)​​

构造 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 类中的几个细节(一)_java

运行结果:

Thread 类中的几个细节(一)_.net_02

那再创建一个 Thread,命名是怎样的呢?

Thread 类中的几个细节(一)_.net_03

运行结果:

Thread 类中的几个细节(一)_java_04

回到 Thread 的无参构造函数:

Thread 类中的几个细节(一)_java_05

查看 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() 方法:

Thread 类中的几个细节(一)_.net_06

如果 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 线程。

输出结果:

Thread 类中的几个细节(一)_System_07

发现还有一个 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

 

举报

相关推荐

0 条评论