Thread 提供的属性和方法
目录
- Thread 提供的属性和方法
- 一.构造方法
- 1.Thread() :
- 2.Thread(Runnable target) :
- 3.Thread(String name) :
- main 线程
- 4.Thread(Runnable target, String name) :
- 二.属性
- 1.ID (getId)
- 2.名称(getName)
- 3.状态(getState)
- 4.优先级 (getPriority)
- 5.是否后台线程 (isDaemon)
- 6.是否存活(isAlive)
- isAlive()
- 7.是否被中断(isUnterrupted)
一.构造方法
1.Thread() :
创建线程对象;
2.Thread(Runnable target) :
使用 Runnable 对象创建线程对象;
3.Thread(String name) :
创建线程对象, 并命名;
起名有一个好处: java 进程运行过程中, 可以通过工具看到每个不同线程的名字.
出现问题时, 更直观的把问题线程和代码关联起来(方便调试),
没起名字, 也有默认名字: Thread-0, Thread-1, Thread-2.
当我们运行此代码
package Thread;
public class Demo1 {
public static void main(String[] args) {
Thread t = new Thread(()->{
while(true){
System.out.println("hello");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"自定义线程");//起名
t.start();
}
}
打开 jconsole - 线程 可以看见
但是我们仔细看下, 这里看不见 main 线程了, 此处并不是main线程没有被创建, 而是其执行太快, 结束而销毁了.
main 线程
main 线程是通过 jvm 中通过 C++ 代码创建出来的, 没有通过 java 中的 Thread 类创建, 也就不会重写 run
4.Thread(Runnable target, String name) :
使用 Runnable 对象创建线程对象, 并命名;
同上
[了解] Thread(ThreadGroup group, Runnable target) : 线程可以被用来分组管理, 分好的组进行批量控制;
这种写法在实际开发中更多的被线程池取代了.
二.属性
1.ID (getId)
是线程的唯一标识, 不同线程 不会重复;
与系统内核的 pcb 的 id 是一一对应但不相同的, 是 jvm 自己搞的一套 id 体系.
java代码无法获取到 pcb 中的 id.
2.名称(getName)
在各种调试工具可用到;
3.状态(getState)
表示线程当前所处的一个情况; (就绪 + 阻塞)
4.优先级 (getPriority)
优先级高的线程理论上更容易被调度到;
有些形同虚设, 优先级还是得看系统调度
5.是否后台线程 (isDaemon)
前台线程 :
此线程不结束, java 进程一定不会结束.(可以有多个, 当最后一个前台线程结束, java进程结束)
在 java 中, main 线程, 就是前台线程. 另外程序员创建出来的线程, 默认情况下都是 前台线程.
后台进程 :
此线程即使继续执行, 也不能阻止 java 进程 结束.(不希望此线程, 影响java进程结束)
可以通过 setDaemon 方法 来把线程设置成 后台线程.
像上图 jvm 内置线程 就是 后台线程
后台线程比如 有的线程负责 gc(垃圾回收) , gc 是要周期性持续性执行的,不可能主动结束.
栗子
package thread;
public class Test {
public static void main(String[] args) {
Thread t = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
//设置为后台线程
//t.setDaemon
t.start();
}
}
未设置为后台线程输出
hello thread
hello thread
hello thread
hello thread
hello thread
Process finished with exit code 0
只要 t 线程 未结束, 进程不结束.
main 执行完, start结束.
设置为后台进程输出
Process finished with exit code 0
当设置t为后台线程, 只有main是前台线程了,
main执行完 start 就结束了.t 线程没来得及打印.(线程之间是抢占式执行).
大概率是什么也不打印.
若将 setDaemon 放在 start 后将会发生什么
package thread;
public class Test {
public static void main(String[] args) {
Thread t = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.start();
//设置为后台线程
t.setDaemon(true);
}
}
Exception in thread "main" java.lang.IllegalThreadStateException
at java.lang.Thread.setDaemon(Thread.java:1359)
at thread.Test.main(Test.java:16)
hello thread
hello thread
hello thread
hello thread
hello thread
Process finished with exit code 1
此处发生了报错, 并且设置后台线程未生效.
关于各种属性设置, 都要放在 start 之前
6.是否存活(isAlive)
指的是系统中的线程 (PCB) 是否还存在.(Thread的生命周期)
Thread 对象的生命周期, 和 PCB 的生命周期是不一定完全相同的.
package thread;
public class Test {
public static void main(String[] args) {
Thread t = new Thread(() -> {
});
t.start();
Thread.sleep(1000);
}
}
因为
Thread t = new Thread(() -> {
});
这个代码已经创建了 Thread 实例, 诞生了Thread对象,
但是, 此时, 内核中的 PCB 没有诞生.
t.start();
这个代码, 才是真正的在系统中创建出线程
PCB 才真正的被创建出来并且加入到链表中.
由于t 线程中什么都没写, 所以t 瞬间结束, 内核中的线程和 pcb 就被销毁了.
但是在 sleep 结束之前, t 引用 指向的 Thread 对象 仍然存在, 并且没有被gc回收.
则会出现, 系统中的线程先结束掉了, 但 t 仍存在.
isAlive()
package thread;
public class Test {
public static void main(String[] args) {
Thread t = new Thread(() -> {
});
t.start();
Thread.sleep(1000);
System.out.println(t.isAlive());
}
}
false
package thread;
public class Test {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
t.start();
Thread.sleep(1000);
System.out.println(t.isAlive());
}
}
true