第一章、线程管理

1.1 简介
并发(Concurrency):一系列任务的同时进行
同时性(Simultaneity)

1.2 线程的创建和运行
1. 继承Thread 类,并覆盖run()方法
2. 创建一个实现Runnable接口的类。使用带参数的Thread构造器来创建Thread对象。这个参数就是实现Runnable接口的类的一个对象

//继承Thread
public class Calculator2 extends Thread {
    private int number;
    public Calculator2(int number){
        this.number = number;
    }
    @Override
    public void run(){
        for(int i=1;i<=10;i++){
            System.out.println(Thread.currentThread().getName()+": "+number+" "+i+" = "+i*number);
        }
    }
    public static void main(String args[]){
        for(int i=1;i<=10;i++){
            Calculator2 calculator = new Calculator2(i);
            calculator.start();
        }
    }
}

//实现Runnable接口
public class Calculator implements Runnable{
    private int number;
    public Calculator(int number){
        this.number = number;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=1;i<=10;i++){
            System.out.println(Thread.currentThread().getName()+": "+number+" * "+i+" = "+i*number);
        }
    }
    public static void main(String args[]){
        for(int i=0; i<=10; i++){
            Calculator calculator = new Calculator(i);
            Thread thread = new Thread(calculator);
            thread.start();
        }
    }

}

工作原理:
每个Java程序都至少有一个执行线程。当运行程序的时候,JVM将启动启动这个执行线程来调用main()方法。
当调用Thread对象的start()方法使时,另一个执行线程将被创建。每次调用一个start()方法都会执行一个新的线程。
当一个程序的所有线程都运行完成时,更明确的说,当所有非守护(non-daemon)线程都运行完成的时候,这个Java程序宣告结束。如果初始线程(执行main()方法的线程)结束了,其余的线程仍将继续执行直到它们运行结束。如果某一线程调用了System.exit()指令来结束程序的执行,所有线程都将结束。
对于一个实现了Runnable()接口的类来说,创建Thread对象并不会创建一个新的执行线程。同样调用它的run方法,也不会创建一个新的执行线程。只有调用它的start()方法,才会创建一个新的执行线程。

1.3线程信息的获取和设置

ID:保存了线程的唯一标示符
Name: 保存了线程的名称
Priority: 保存了线程对象的优先级。线程的优先级从低到高是从1到10。(并不推荐去改变线程的优先级)
Status: 保存了线程的状态。在Java中,线程的状态有6种:new、runnable、blocked、waiting、time waiting或者terminated。(新建、运行、锁池、等待、定时等待、终止)

1.4线程的中断
Java提供了中断机制,可以使用它来结束一个线程。这种机制要求线程检查它是否被中断了,然后决定是不是响应这个中断请求。线程允许忽略中断请求并且继续执行。

1.5线程中断的控制
Java提供了InterruptException异常来控制线程的中断。当检查到线程中断的时候就抛出这个异常,然后在run()中捕获并处理这个异常。

1.6线程的休眠和恢复

thread.interrupted()方法发出的是通知程序线程应该中断,即抛出一个InterruptedException异常,由程序自身来处理是否中断。

1.7等待线程的终止
在执行其他任务的时候,必须先初始化一些必须的资源。可以使用线程来完成这些初始化任务,等待线程的终止,再执行程序的其他任务
Thread类的join()方法,当该方法被调用时,调用它的线程将被挂起,知道这个线程对象完成它的任务

join() 等待线程结束,继续运行
join(long milliseconds) 等待线程结束或者到达时间
join(long milliseconds, long nanos) 等待线程结束或者到达时间

1.8守护线程的创建和运行
守护(Daemon)线程:当同一个应用程序没有其他线程运行的时候,守护线程才运行。当守护线程是程序中唯一运行的程序,守护线程之行结束后,JVM也就结束了这个程序
守护线程通常用来作为同一程序中普通线程(也称为用户线程)的服务提供者。它通常是无限循环的,以等待服务请求或者执行线程的任务。它们不能做重要的工作,因为不知道守护线程什么时候能够获取CPU时钟,并且在没有其他线程运行的时候,守护线程随时可能结束。一个典型的守护进程就是Java的垃圾回收机制(Garbage Collector)

setDaemon()方法只能在start()方法被调用之前设置。一旦线程开始运行,将不能再修改守护状态。
isDaemon()用来检查是否是守护线程。

1.9线程中不可控制的异常
非运行异常(Checked Exception):必须在方法生命的throws语句指定或者在方法体内捕获
运行时异常(Unchecked Exception)

当一个线程抛出异常并且没有被捕获时(运行时异常),JVM检查这个线程是否被预置了未捕获异常处理器,如果找到,JVM将调用线程对象的这个方法,并将线程对象和异常作为传入参数。
如果线程没有被预置未捕获异常处理器,JVM将打印堆栈记录到控制台,并退出程序。

Thread还有另外一个方法可以处理未捕获的异常,即静态方法setDefaultUncaughtExceptionHandler()。这个方法在应用程序中为所有的线程对象创建一个异常处理器。
当线程抛出一个未捕获到的异常时,JVM将为异常寻找以下三种可能的处理器。
首先,查找线程对象的未捕获异常处理器。如果找不到,JVM继续查找线程对象所在线程组(ThreadGroup)的未捕获异常处理器,如果还是找不到,JVM将继续查找默认的未捕获处理器。

1.10 线程局部变量的使用
(Thread-Local Variable)
在一个task被多个线程运行的时候,那么这个task中的属性就成了共享属性,但是有时候,我们并不想变量被所有线程共享,这个时候 就要用到 线程局部变量(Thread-Local Variable)机制了.
很简单的使用,就不示例了.伪代码,把loc 用ThreadLocal来包装,并初始化. 而不是使用private Date date;

    ThreadLocal<Date> loc = new ThreadLocal<Date>(){
        @Override
        protected Date initialValue() {
            return new Date();
        }
    };
    Date date = loc.get();  //获取值
    System.out.println("开始时间:" + date);
    loc.set(new Date()); //设置值
    System.out.println("结束时间:" + loc.get());
    loc.remove(); //删除值

InheritableThreadLocal : 也是一种局部变量,不过它是用于给子线程 获取父线程的 局部变量的.假如:A线程创建了B线程.线程B的局部变量和A的局部变量是一样的.也可以覆盖childValue()方法,这个方法用来初始化子线程在线程局部变量中的值.它使用父线程在线程局部变量中的值作为参数传入.

1.11线程的分组
把一个组的线程当成一个单一的单元,对组内线程对象进行访问并操作它们。
Java提供ThreadGroup类表示一组线程,线程组可以包含线程对象,也可以包含其他的线程组对象,它是一个树形结构。

1.12线程组中不可控异常的处理
extends ThreadGroup
重写 uncaughtException(Thread t, Throwable e) 方法.只要该线程组中有抛出异常的,该方法就会被调用

1.13 使用工厂类创建线程
Java提供了ThreadFactory接口,实现了线程对象工厂。
只有一个方法newThread,它以Runnable接口对象作为传入参数并且返回一个线程对象,当实现ThreadFactory接口时,必须实现覆盖这个方法。

猜你喜欢

转载自blog.csdn.net/a1561067921/article/details/80220168