ThreadLocal

每个线程都有自己的工作内存,使用ThreadLocal类创建工作内存中的变量,不同线程访问同一个Threadlocal对象时,获取到的数据是存储在工作内存上的数据

public static void main(String[] args) throws InterruptedException {
    ThreadLocal<String> local = new ThreadLocal<>();  //注意这是一个泛型类,存储类型为我们要存放的变量类型
    Thread t1 = new Thread(() -> {
        local.set("lbwnb");   //将变量的值给予ThreadLocal
        System.out.println("变量值已设定!");
        System.out.println(local.get());   //尝试获取ThreadLocal中存放的变量
    });
    Thread t2 = new Thread(() -> {
        System.out.println(local.get());   //尝试获取ThreadLocal中存放的变量
    });
    t1.start();
    Thread.sleep(3000);    //间隔三秒
    t2.start();
}

上面的代码中t1​访问local​存放的变量为t1​线程中设置的“lbwnb”,但是t2并没有在线程中设置local​的变量值,所以在访问local​存放的值时返回的null

在线程中创建子进程,无法获得父进程工作内存中的变量:

public static void main(String[] args) {
    ThreadLocal<String> local = new ThreadLocal<>();
    Thread t = new Thread(() -> {
       local.set("lbwnb");
        new Thread(() -> {
            System.out.println(local.get());
        }).start();
    });
    t.start();
}

使用inheritableThreadLocal来解决

public static void main(String[] args) {
    ThreadLocal<String> local = new InheritableThreadLocal<>();
    Thread t = new Thread(() -> {
       local.set("lbwnb");
        new Thread(() -> {
            System.out.println(local.get());
        }).start();
    });
    t.start();
}

定时器

public static void main(String[] args) {
    Timer timer = new Timer();    //创建定时器对象
    timer.schedule(new TimerTask() {   //注意这个是一个抽象类,不是接口,无法使用lambda表达式简化,只能使用匿名内部类
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName());    //打印当前线程名称
        }
    }, 1000);    //执行一个延时任务
}

使用Timer创建定时任务,任务虽然执行完成了,但是我们的程序并没有停止,因为Timer内存维护了一个任务队列和一个工作线程,TimerThread继承自Thread,是一个新创建的线程,在构造时自动启动,而它的run方法会循环的读取队列中是否还有任务,如果有任务依次执行,没有的话就暂时处于休眠状态。如果要让程序自动关闭,我们可以调用Timer的cancel()​方法以正常退出程序

守护线程

在主线程中创建一个子线程,通过测试可以发现主线程已经结束但是子线程依旧在执行,而守护线程会当所有的非守护线程结束后,自动结束,也就是说,java中所有的线程都执行完毕后,守护线程会自动结束,因此守护线程不适合进行IO操作

public static void main(String[] args) throws InterruptedException{
    Thread t = new Thread(() -> {
        while (true){
            try {
                System.out.println("程序正常运行中...");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    t.setDaemon(true);   //设置为守护线程(必须在开始之前,中途是不允许转换的)
    t.start();
    for (int i = 0; i < 5; i++) {
        Thread.sleep(1000);
    }
}

注意:在守护线程中创建新的线程也是守护的