Thread构造函数
1.Thread构造函数有哪些
public Thread();
public Thread(Runnable target);
public Thread(ThreadGroup group, Runnable target);
public Thread(String name);
public Thread(ThreadGroup group, String name);
public Thread(Runnable target, String name);
public Thread(ThreadGroup group, Runnable target, String name);
public Thread(ThreadGroup group, Runnable target, String name,long stackSize);
以上是Thread相关的构造函数源码
2.线程的命名
2.1线程的默认命名
线程的默认命名是:"Thread-"作为前缀与一个自增长数字进行字母组合,这个自增数字在整个JVM进程中将会不断自增;
默认命名的自增代码如下:
public static void main(String[] args) {
IntStream.range (0, 5).boxed ().map (
i -> new Thread (() -> System.out.println (Thread.currentThread ().getName ()))).forEach (Thread::start);
}
控制台打印输出如下:
Thread-0
Thread-2
Thread-1
Thread-3
Thread-4
Thread-5
2.2修改线程的命名
修改线程的实例代码如下:
private final static String PREFIX = "HELLO-";
public static void main(String[] args) {
IntStream.range (0,5).mapToObj (ThreadNameTest1::createThread).forEach (Thread::start);
}
private static Thread createThread(final int intName) {
return new Thread (() -> System.out.println (Thread.currentThread ().getName ()), PREFIX + intName);
}
控制台打印输出:
HELLO-0
HELLO-1
HELLO-2
HELLO-3
HELLO-4
从上面的线程可以看出,线程是可以修改名称的,并且给线程的命名有助于在实际开发中追踪线程的并发问题
3.线程的父子关系
在Thread的构造方法中都会去调用一个init构造方法,新创建的任何一个线程都会有一个父线程
1. 一个线程的创建是另一个线程完成的;
2. 被创建线程的父线程是创建它的线程;
Thread中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) {
/* Determine if it's an applet or not */
/* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}
/* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
g.checkAccess();
/*
* Do we have the required permissions?
*/
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();
}
4.线程和线程组
线程与线程组的关系代码测试如下:
Thread t1 = new Thread ("t1");
ThreadGroup group = new ThreadGroup ("TestGroup");
Thread t2 = new Thread (group, "t2");
ThreadGroup mainGroupThread = Thread.currentThread ().getThreadGroup ();
System.out.println ("主线程是哪个线程组:" + mainGroupThread.getName ());
System.out.println ("t1线程和主线程是相同的组:" + (mainGroupThread == t1.getThreadGroup ()));
System.out.println ("t2线程不属于主线程组:" + (mainGroupThread == t2.getThreadGroup ()));
System.out.println ("t2线程组是属于主线程TestGroup的组:" + (t2.getThreadGroup ()== group));
控制台输出:
主线程属于哪个组:main
t1线程和主线程是相同的组:true
t2线程组不属于主线程组:false
t2线程组是属于主线程TestGroup的组:true
分析线程和线程组的关系得出:
- main线程所在的ThreadGroup称为:main;
- 构造一个线程的时候没有显示的执行ThreadGroup,它就和父线程同属于一个ThreadGoup
5.Thread与Runnable
Thread负责的是线程本身相关的职责和控制,而Runnable则负责逻辑执行单元的部分
6.守护线程
6.1守护线程的概念
守护线程是后台线程,也就是执行的自定义线程,如果JVM中没有一个非守护线程,JVM的进程就会推出
6.2守护线程的作用
守护线程经常用作与执行后台任务,因此有时它也称为后台线程,当你希望关闭某些线程的时候,或者推出JVM进程的时候,一些线程能够自动关闭,此时可以考虑守护线程来完成这样的工作
6.2守护线程的代码测试
public static void main(String[] args) {
Thread thread = new Thread (() -> {
while (true) {
try {
Thread.sleep (100);
} catch (InterruptedException e) {
e.printStackTrace ();
}
}
});
thread.setDaemon (true);// 设置为守护线程
thread.start ();
System.out.println ("finally");
}
设置守护线程,调用setDaemon (true)方法即可,设置守护线程只能在线程启动之前进行设置,如果一个线程已经死亡了,那么再设置setDaemon ()就会抛出异常 IllegalThreadStateException
Exception in thread "main" java.lang.IllegalThreadStateException
at java.lang.Thread.setDaemon(Thread.java:1352)
at com.hyq.thread.threadtest.ThreadDaemon.main(ThreadDaemon.java:22)