并发和多线程--线程相关属性和线程异常处理
Posted huigelaile
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并发和多线程--线程相关属性和线程异常处理相关的知识,希望对你有一定的参考价值。
1、线程id和name
线程id是线程的唯一标识,不可修改,而线程名称是可以修改的。
public static void main(String[] args) { Thread thread = new Thread(); System.out.println("主线程ID为:"+Thread.currentThread().getId()); System.out.println("主线程ID为:"+thread.getId()); System.out.println("主线程name为:"+thread.getName()); thread.setName("thread58"); System.out.println("主线程name为:"+thread.getName()); }
结果: 主线程ID为:1 主线程ID为:12 主线程name为:Thread-0 主线程name为:thread58
从结果看到,主线程的id为1,所以线程的id也是从1开始的,而新建的子线程的id为12,而不是我们猜想的2。
通过查看源码,知道线程id的规则如下:
public long getId() { return tid; } //通过调用Thread构造器初始化Thread,而tid = nextThreadID() public Thread() { init(null, null, "Thread-" + nextThreadNum(), 0); } private static synchronized long nextThreadID() { return ++threadSeqNumber; }
这里是++threadSeqNumber实现自增,那为什么子线程的id不是2呢,是因为Jvm在运行代码的时候还会启动别的线程帮助程序运行和处理,例如垃圾
收集器等,通过debug我们就可以看到。
而线程的name值,只是对线程的命名,除了默认情况下的命名,我们还可以通过setName()修改,而且可以多个线程name相同。
public Thread() { init(null, null, "Thread-" + nextThreadNum(), 0); } private static synchronized int nextThreadNum() { return threadInitNumber++; }
通过源码看到,默认没有name的情况下,通过"Thread-" + nextThreadNum()进行命名,而这个方法是threadInitNumber++,所以从Thread-0开始。
2、守护线程
对于jvm来说,一般我们创建的线程都是用户线程,除了用户线程就是守护线程,守护线程为了程序运行而服务,守护用户线程。一般来说,守护线程
被jvm启动,而用户线程被主线程启动。根本的区别就是,如果jvm发现没有当前没有用户线程在运行,jvm就会退出,守护线程对jvm退出没有影响。
线程类型默认继承父线程,例如,在main方法中创建一个线程,主线程就是用户线程,所以被创建的线程默认也是用户线程。同样的,守护线程创建的
线程也是守护线程。
//判断当前线程是否Wie守护线程 public final boolean isDaemon() { return daemon; } //设置当前线程为守护线程。true,守护线程,false,用户线程 public final void setDaemon(boolean on) { checkAccess(); if (isAlive()) { throw new IllegalThreadStateException(); } daemon = on; }
PS:
开发过程中,不要将线程设置为守护线程,一旦设置为守护线程,jvm发现没有用户线程在运行,就直接关闭了,就会导致我们的程序没有执行完就
关闭了。
3、线程优先级
线程优先级是指线程启动执行的优先级,对于Java来说,一共10个优先级,默认为5。准确的说,线程优先级也是继承父类优先级,如果你把主函数设置
为8,新建的子线程默认也是8.
/** * The minimum priority that a thread can have. */ public final static int MIN_PRIORITY = 1; /** * The default priority that is assigned to a thread. */ public final static int NORM_PRIORITY = 5; /** * The maximum priority that a thread can have. */ public final static int MAX_PRIORITY = 10; //设置线程优先级 public final void setPriority(int newPriority) { } //获取线程优先级 public final int getPriority() { return priority; }
开发中,我们不应该依赖线程优先级,因为我们在使用多线程的时候,发现优先级高的线程不一定比优先级低的线程先执行,只能说概率更高而已。
而且,1-10的优先级只是jvm的划分,总归要和OS挂钩的,不同的OS对优先级的划分不同,需要进行映射。例如Windows有7个优先级,1,2对1,3,4对
2。。。而Linux系统下Java线程优先级会被忽略,不能起作用。在solaris系统中,又是不同的。
设置线程优先级,还有可能带来的问题,就是某些优先级低的线程可能一直无法获得CPU使用权,也就是一直保持"饥饿"状态。所以,综上,完全不
建议修改线程优先级。
4、如何捕获线程异常?
public static void main(String[] args) { Thread thread = new Thread(new ThreadClass()); thread.start(); for (int i = 0; i < 100; i++) { System.out.println(i); } } @Override public void run() { throw new RuntimeException(); }
通过上面的代码的运行,可以看到,子线程发生异常,主线程还是继续运行,如果运行在服务器上面,可能都不知道程序有出现过异常。所以,我们需要
对Thread的代码进行异常处理,例如try catch。
try catch处理线程异常:
public static void main(String[] args) { Thread thread = null; Thread thread1 = null; Thread thread2= null; Thread thread3 = null; try { thread = new Thread(() -> { throw new RuntimeException(); }); thread1 = new Thread(() -> { throw new RuntimeException(); }); thread2 = new Thread(() -> { throw new RuntimeException(); }); thread3 = new Thread(() -> { throw new RuntimeException(); }); } catch (RuntimeException e) { e.printStackTrace(); } thread.start(); thread1.start(); thread2.start(); thread3.start(); for (int i = 0; i < 100; i++) { System.out.println(i); } }
四个线程都发生异常,我们通过try catch去处理,发现还是同样的结果。一个线程抛出异常,其他三个还有主线程还是会继续执行。
正确的方式:
明天再写,困了!
以上是关于并发和多线程--线程相关属性和线程异常处理的主要内容,如果未能解决你的问题,请参考以下文章