Thread的几个常用属性判断
属性 | 获取方法 |
---|---|
ID | getId() |
名称 | getName() |
状态 | getState() |
优先级 | getPriority() |
是否守护线程(后台线程) | isDaemon() |
是否存活 | isAlive() |
是否被中断 | isInterrupted() |
- ID:是线程的唯一标识,不同线程不会重复
- 名称:各种调试工具用到
- 状态:表示线程当前所处的一个情况
- 优先级:优先级高的线程理论上来说更容易被调度
- 守护(后台)线程:JVM会在一个进程的所有非后台线程结束后,才会结束运行
- 是否存活:简单理解为 run() 方法是否运行结束
- 是否中断
线程ID,名称
- 每个线程的id一定是不相同的,是动态分配的
- 线程名称是可以手动指定的,并且线程名称是可能存在重复的情况
public class ThreadDemo1 {
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
@Override
public void run() {
Thread t = Thread.currentThread();
System.out.println(t.getName()+"线程ID:"+t.getId());
System.out.println(t.getName()+"线程名称:"+t.getName());
}
};
Thread threadA = new Thread(runnable,"线程A");
threadA.start();
Thread threadB = new Thread(runnable,"线程B");
threadB.start();
Thread threadC = new Thread(runnable,"线程C");
threadC.start();
}
}
线程状态
public class ThreadDemoGetState {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Thread t = Thread.currentThread();
System.out.println("线程状态1:"+t.getState());
}
});
System.out.println("线程状态:"+ thread.getState());
thread.start();
Thread.sleep(500);
System.out.println("线程状态2:"+thread.getState());
}
}
线程优先级
获取线程优先级
线程创建之后,线程优先级就存在了
优先级是int类型,线程的优先级为1~10,最低的优先级是1,最高的优先级是10,默认的优先级是5。
public class ThreadDemoGetPriority {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Thread t = Thread.currentThread();
System.out.println("线程优先级1:"+t.getPriority());
}
});
System.out.println("线程优先级2:"+thread.getPriority());
thread.start();
Thread.sleep(500);//休眠0.5s
System.out.println("线程优先级3:"+thread.getPriority());
}
}
设置线程优先级
setPriority()
public class ThreadDemoSetPriority {
private final static int MAX_COUNT = 1000;
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
//得到当前线程
Thread t = Thread.currentThread();
int priority = t.getPriority();
for (int i = 0;i<MAX_COUNT;i++){
System.out.println(t.getName()+"-优先级:"+priority);
}
}
},"线程A");
thread1.setPriority(Thread.MAX_PRIORITY);
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
Thread t = Thread.currentThread();
int priority = t.getPriority();
for (int i = 0; i < MAX_COUNT; i++) {
System.out.println(t.getName()+"-优先级:"+priority);
}
}
},"线程B");
thread2.setPriority(Thread.MIN_PRIORITY);
Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
Thread t = Thread.currentThread();
int priority = t.getPriority();
for (int i = 0; i < MAX_COUNT; i++) {
System.out.println(t.getName()+"-优先级:"+priority);
}
}
},"线程C");
thread3.setPriority(5);
thread2.start();
thread1.start();
thread3.start();
}
}
注意事项:同时启动多个线程,多个线程设置了不同的优先级,并不是优先级最高的就一定先执行完后再执行优先级低的线程,而是高优先级的线程获取到CPU时间片的概率更大,整个的执行大致符合高优先级的线程最先执行完的。
守护线程(后台线程)
线程分类:
- 用户线程(main默认为用户线程)
- 守护线程:为用户线程服务的,当一个程序中的所有用户线程都执行结束后,那么守护线程也会随之结束。
thread.isDaemon();//判断是否为守护线程
thread.setDaemon(true);//设置守护线程
当前线程是否为守护线程:true=守护线程,false=用户线程
public class ThreadDemoIsDaemon {
public static void main(String[] args) throws InterruptedException {
Thread thread = Thread.currentThread();
System.out.println(thread.getName()+"--是否为守护线程:"+thread.isDaemon());
Thread t1 = new Thread(()->{
Thread cThread = Thread.currentThread();
System.out.println(cThread.getName()+"--是否为守护线程:"+cThread.isDaemon());
Thread tt1 = new Thread(()->{
Thread cThread2 = Thread.currentThread();
System.out.println(cThread2.getName()+"--是否为守护线程:"+cThread2.isDaemon());
},"子线程的子线程A");
tt1.start();
},"子线程A");
//手动指定线程为守护线程
t1.setDaemon(true);
t1.start();
//主线程休眠1s
Thread.sleep(1000);
}
}
结论
- main线程(主线程)默认是非守护线程(用户线程)
- 在用户线程中创建的子线程默认情况下也是用户线程
- 在守护线程中创建的子线程默认情况下也是守护线程
注意事项:线程的类型(用户or守护)不能在线程运行期间,也就是调用了start() 之后进行设置,如果设置那么JVM会保错
用户线程:
public class userThread {
public static void main(String[] args) {
Thread thread = new Thread(()->{
for (int i = 0; i < 10; i++) {
System.out.println("执行:"+i);
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
}
}
守护线程:
public class daemonThread {
public static void main(String[] args) {
Thread thread = new Thread(()->{
for (int i = 0; i < 10; i++) {
System.out.println("执行:"+i);
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
//将线程设置为守护线程
thread.setDaemon(true);
//启动线程
thread.start();
}
}
结论:JVM会等待所有的用户线程全部执行结束后再退出,但是JVM不会等待守护线程执行结束再推出
守护线程 VS 用户线程:
用户线程在Java程序中很重要,JVM一定要等所有的用户线程执行结束后才能自然退出;而守护线程就不一样了,守护线程是为用户线程服务的,所以当所有的用户线程执行结束后,不管守护线程是否执行结束,JVM都会退出执行。
线程存活
public class ThreadDemoByAlive {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
Thread t = Thread.currentThread();
System.out.println(t.getName()+"--线程是否存活:"+t.isAlive());
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("线程执行完了!");
});
thread.start();
//线程如果一直存活,即thread.isAlive()一直为真,将不会执行后面的打印
while (thread.isAlive()){
}
System.out.println("确认线程thread执行完了!");
}
}
线程终止
使用自定义标识符来终止线程
public class ThreadInterrupt1 {
//声明一个自定义标识符
private volatile static boolean flag = false;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
while (!flag){
System.out.println("正在转账。。。");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("溜了溜了");
});
thread.start();
Thread.sleep(1000);
//终止线程
System.out.println("有内鬼,终止交易");
flag = true;
}
}
使用interrupt()
终止线程
public class ThreadInterrupt2 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
System.out.println("终止标志位A:"+Thread.currentThread().isInterrupted());
while (!Thread.currentThread().isInterrupted()){
System.out.println("正在转账。。。");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
System.out.println("???");
System.out.println("终止标志位B:"+Thread.currentThread().isInterrupted());
});
thread.start();
Thread.sleep(100);
//终止线程
thread.interrupt();
System.out.println("有内鬼,终止交易");
System.out.println("终止标志位C:"+thread.isInterrupted());
}
}
interrupt()
需要配合 Thread.interrupted()
或 Thread.currentThread().isInterrupted()
一起使用,从而实现线程的终止
isInterrupted()
和interrupted()
的区别:
interrupted()
属于静态方法,所有程序都可以直接调用的全局方法;而isInterrupted()
属于某个实例的方法interrupted()
在使用完之后会重置中断标识符;而isInterrupted()
不会重置中断标识符
关于线程的执行顺序
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
@Override
public void run() {
Thread t = Thread.currentThread();
System.out.println(t.getName()+"线程ID:"+t.getId());
System.out.println(t.getName()+"线程名称:"+t.getName());
System.out.println(t.getName()+"线程优先级:"+t.getPriority());
}
};
Thread threadA = new Thread(runnable,"线程A");
threadA.start();
Thread threadB = new Thread(runnable,"线程B");
threadB.start();
Thread threadC = new Thread(runnable,"线程C");
threadC.start();
}
}
下面是经过多次运行的结果
结论:
- 每个线程内执行的顺序都是从上到下按顺序执行
- 多个线程间的执行的顺序是“随机”的
一些其他方法join()、yield()
join()
等待某个线程执行结束后,再执行后续的代码
//等待线程thread执行结束后,再执行后续代码
thread.join();
优点:运行时所用的资源更少
yield()
让出CPU的执行权
public class ThreadYield {
public static void main(String[] args) {
Thread thread = new Thread(()->{
//得到当前线程
Thread cThread = Thread.currentThread();
for (int i = 0; i < 100; i++) {
//让出CPU执行权
Thread.yield();
System.out.println(cThread.getName());
}
},"张三");
thread.start();
//创建并启动线程
new Thread(()->{
Thread cThread = Thread.currentThread();
for (int i = 0; i < 100; i++) {
System.out.println(cThread.getName());
}
},"李四").start();
}
}
注意事项:yield()
方法虽然会出让CPU的执行权,让线程调度器重新调度线程,但还是有一定的机率再一次调用到让出CPU的线程上的,这一次他就会执行让出线程的方法了,因为yield()
已经被执行过了。