ThreadLocal

ThreadLocal直译为线程局部变量

特点

  1. 只能在自己的线程内访问自己的数据,另外的线程是访问不到其他ThreadLocal的
ThreadLocal<Person> tl = new ThreadLocal<>();

new Thread(() -> {
SleeperHelper.sleepSecond(1);
tl.set(new Person("zhangsan"));
System.out.println(tl.get());
}).start();

new Thread(() -> {
SleeperHelper.sleepSecond(2);
System.out.println(tl.get());
}).start();


// 输出对象地址
// null

应用场景

  1. Spring事务处理方案(@Transaction)
  2. 存储全局用户登录信息
  3. 存储数据库连接,以及Session等信息

内存

内存溢出

内存空间装满了,这时再进入对象,没法分配空间,就会报内存溢出错误(out of memory)

内存泄漏

内存还有空余的位置,但是内存中存着一个被强引用指着的对象,该对象在业务逻辑上已经不使用了,但是这个对象又不能被回收,后面的程序也不使用,这就是内存泄漏

内存溢出与内存泄漏的关系:如果内存泄漏太多,就会引起内存溢出

引用类型

Java中4种引用的级别由高到低依次为:强引用 > 软引用 > 弱引用 > 虚引用

强引用

只要强引用存在,垃圾回收器将永远不会回收被引用的对象,哪怕内存不足时,JVM也会直接抛出OutOfMemoryError,不会去回收。

如果想中断强引用与对象之间的联系,可以显示的将强引用赋值为null,这样一来,JVM就可以适时的回收对象了。

使用new创建对象时,被创建的对象就是强引用,如Object object = new Object(),其中的object就是一个强引用了。

软引用

“内存不够就回收,内存充足不回收”

“适合做缓存”

在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。

JDK1.2 之后,用java.lang.ref.SoftReference类来表示软引用。

如果一个对象只具备软引用,如果内存空间足够,那么JVM就不会GC它,如果内存空间不足了,就会GC该对象。

应用

  1. 软引用是用来描述一些非必需但仍有用的对象。这种特性常常被用来实现缓存技术,比如网页缓存,图片缓存等。

弱引用

弱引用的引用强度比软引用要更弱一些,无论内存是否足够,只要 JVM 开始进行垃圾回收,那些被弱引用关联的对象都会被回收。

在 JDK1.2 之后,用 java.lang.ref.WeakReference 来表示弱引用。

弱引用的生命周期要比软引用短很多。不过,如果垃圾回收器是一个优先级很低的线程,也不一定会很快就会释放掉软引用的内存。

如果一个对象只具有弱引用,只要JVM的GC线程检测到了,就会立即回收。

虚引用

虚引用是最弱的一种引用关系。

在 JDK1.2 之后,用 PhantomReference类来表示,通过查看这个类的源码,发现它只有一个构造函数和一个 get() 方法,而且它的 get() 方法仅仅是返回一个null,也就是说将永远无法通过虚引用来获取对象,虚引用必须要和 ReferenceQueue引用队列一起使用。

如果一个对象只具有虚引用,那么它就和没有任何引用一样,随时会被JVM当作垃圾进行GC。

应用

  1. 设置虚引用关联的唯一目的,就是能在这个对象被收集器回收时收到一个系统通知
PhantomReference a = new PhantomReference(new A(), referenceQueue); // 必须配合引用队列一起使用
  1. 追踪堆外数据

线程池

线程池是一种用于管理线程资源的机制,它可以在应用程序启动时创建一定数量的线程,然后将任务提交给线程池进行执行。线程池可以有效地避免线程创建和销毁的开销,提高了线程的复用性和执行效率。

线程池通常包含两个部分:线程池管理器和工作线程。线程池管理器负责创建、销毁、监控线程池,以及分配任务给工作线程;工作线程则负责执行具体的任务。

优势

  1. 提高了程序的响应速度:使用线程池可以避免线程创建和销毁的开销,从而提高程序的响应速度。
  2. 提高了线程的复用性:线程池中的线程可以被重复利用,从而提高了线程的复用性。
  3. 提高了执行效率:线程池可以控制线程的数量,从而避免了过多线程竞争资源的问题,提高了执行效率。
  4. 提高了程序的稳定性:线程池可以对线程进行统一的管理和监控,从而保证了程序的稳定性和安全性。 总之,线程池是一种非常有用的多线程编程技术,它可以提高程序的性能和稳定性,降低线程创建和销毁的开销,是开发高并发程序的重要手段之一。

eg:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void main(String[] args) {
// 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(5);
// 提交任务到线程池
for (int i = 0; i < 10; i++) {
Runnable worker = new WorkerThread("Task " + (i + 1));
executor.execute(worker);
}
// 关闭线程池
executor.shutdown();
while (!executor.isTerminated()) {
}
System.out.println("All tasks completed");
}
}
class WorkerThread implements Runnable {
private String taskName;
public WorkerThread(String taskName) {
this.taskName = taskName;
}
public void run() {
System.out.println(Thread.currentThread().getName() + " Start executing task: " + taskName);
processTask();
System.out.println(Thread.currentThread().getName() + " End executing task: " + taskName);
}
private void processTask() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

// 这个例子中,我们创建了一个大小为5的线程池,然后提交了10个任务到线程池中。每个任务是一个WorkerThread对象,它实现了Runnable接口,表示它是一个可以在线程池中执行的任务。在每个任务中,我们简单地输出一些信息,并且让线程休眠2秒钟,模拟任务执行的过程。最后,我们关闭了线程池,等待所有任务执行完毕,然后打印一条“所有任务已完成”的消息。