多线程学习笔记:6.线程常用概念和方法

1.休眠

调用sleep()方法可以让线程睡眠指定时间。调用后线程进入超时等待状态。

2.优先级

线程的优先级为1—10共10个级别。调度器倾向于让优先级高的线程先执行。所以优先级越高,被执行的频率就越高。

线程的默认优先级为5.可以使用getPriority()方法获取当前线程优先级,使用setPriority()方法设置线程优先级。

JDK的10个优先级与多数操作系统不能很好的映射,所以当调整优先级时优先使用MAX_PRORITY、NORM_PRORITY、MIN_PRORITY.这三种级别可以很好的在不同操作系统中映射。在JDK中分别对应10,5,1.

3.让步

调用yeild()方法可以让当前线程从running回到ready状态,然后与具有相同或更高优先级的线程一起争夺CPU的执行权。                 自己的理解是每个线程都在通过操作系统的线程调度分配到cpu的时间片,当当前线程调用yeild方法后,该线程放弃分配到的时间片。然后在分配下次时间片时,只有具有相同或更高优先级的线程参与。到下下次分配时间片时,所有优先级的线程都可以参与了。所以只有这一次分配是可以保证低优先级的是不会运行的。

4.后台线程

后台线程是指在程序运行时在后台提供一种同一服务的线程。当所有非后台线程结束时,程序会杀死进程中的所有后台线程,终止程序。线程默认是非后台线程,可以在线程启动前调用setDaemon()方法,将当前线程设置为后台线程。

public class Test1 {
    public static void main(String[] args) throws InterruptedException {
        Task task = new Task();
        Thread t = new Thread(task,"thread");
        t.setDaemon(true);
        t.start();
        System.out.println("main方法执行结束");
    }
}
class Task implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i <5; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }

    }
}

运行结果:
main方法执行结束
thread0
thread1
thread2

如上,主线程执行完后,后台线程并没有执行完也结束了。

后台线程中创建的线程都会被自动设置成后台线程。

5.加入一个线程

如果某个线程在另一个线程t上调用了t.join(),该线程会被挂起,直到线程t运行结束,或者设置的挂起时间到。

如上图,主线程要等到线程t运行结束后才会接着运行。

简化join方法代码如下:

public final synchronized void join(long millis)
    throws InterruptedException {
                wait(delay);            
        }
    }

 可以知道join是个同步方法,在它内部调用了wait()方法。结合测试代码知道是线程t调用了wait方法,为什么是主线程挂起了,而不是线程t.?

我们知道wait方法是Object中的方法,及每个类都有,调用wait方法后,挂起的线程是wait方法所在的线程,而与谁调用它无关。在测试代码中,虽然是线程t调用的wait()方法,但是这条语句是在main线程中执行的,而不是t线程的run方法中。所以挂起的还是main线程。

6.捕获异常

多线程中,其他线程运行时产生的异常,mian线程是无法进行捕获的。必须在该线程中自己处理。处理方式有两种:                      1.在可能产生异常的地方使用try-catch语句。                                                                                                                                    2.实现Thread.UncaughtExceptionHandler接口

 public interface UncaughtExceptionHandler {
        void uncaughtException(Thread t, Throwable e);
    }

uncaughtException方法会在线程因未捕获的异常而临近死亡时调用。

public class Test1 {
    public static void main(String[] args) throws InterruptedException {
        Task task = new Task();
        Thread t = new Thread(task,"thread");
        t.setUncaughtExceptionHandler(new MyuncaughtExceptionHandler());
        t.start();
        System.out.println("main方法执行结束");
    }
}
class Task implements Runnable{

    @Override
    public void run() {
        System.out.println("抛出一个异常");
        throw new RuntimeException();
    }
}
class MyuncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("捕获并处理异常");
    }
}

 运行结果:

main方法执行结束
抛出一个异常
捕获并处理异常

 可以看到,在线程抛出异常后,会回调未捕捉异常处理器处理异常。

未捕捉异常处理器有两种,如下:

   //每个线程设置自己的异常处理器
    private volatile UncaughtExceptionHandler uncaughtExceptionHandler;

    //所有线程共享的异常处理器
    private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;

参考资料;《java编程思想》

猜你喜欢

转载自blog.csdn.net/qq_42283110/article/details/86665543