并发和多线程(五)--线程相关属性和线程异常处理

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去处理,发现还是同样的结果。一个线程抛出异常,其他三个还有主线程还是会继续执行。

正确的方式:

猜你喜欢

转载自www.cnblogs.com/huigelaile/p/11749209.html
今日推荐