ThreadLocal

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

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​线程中设置的 “lb­wnb”,但是 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(); }

使用 in­her­i­ta­bleThread­Lo­cal 来解决

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); } }

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