Tại sao ThreadLocal có thể gây ra memory leak trong các ứng dụng Java?

Các bạn có biết ThreadLocal có thể gây ra memory leaks trong các ứng dụng Java hay không? Có đó các bạn! Vấn đề không phải do bản thân ThreadLocal, mà do chúng ta sử dụng nó không đúng cách với thread pool.

Khi các bạn gọi phương thức set() của ThreadLocal, giá trị này sẽ được nắm giữ bên trong thread hiện tại. Nếu thread này hoàn tất việc execute tác vụ, Garbage Collector sẽ collect nó.

Nhưng với thread pool, thread sẽ không mất đi. Nó sẽ được reuse để process cho các tác vụ khác.

Các bạn hãy tưởng tượng, request A lưu trữ UserContext trong một đối tượng ThreadLocal. Sau khi request này hoàn tất, thread sẽ được return trở lại pool. Nếu các bạn quên gọi phương thức remove() để remove đối tượng UserContext thì đối tượng này sẽ luôn luôn tồn tại cùng với thread. Nếu thread này handle cho một request B khác, giá trị cũ của đối tượng UserContext vẫn còn tồn tại. Việc này không chỉ ở chỗ ứng dụng của chúng ta lưu trữ một đối tượng không cần thiết trong memory mà còn liên quan đến việc dữ liệu của tác vụ này bị rò rỉ cho các tác vụ khác, đó các bạn!

Giải pháp để giải quyết vấn đề này thì cực kỳ đơn giản, các bạn chỉ cần nhớ là cần clean up đối tượng ThreadLocal sử dụng phương thức remove() sau khi hoàn tất tác vụ.

Các bạn có thể sử dụng try-finally block:

Ví dụ như sau:

Trong ví dụ này thì như các bạn thấy, sau khi thực hiện tác vụ, mình đã gọi phương thức remove() trong try-finally block để remove giá trị trong ThreadLocal đi.

Kết quả:

Các bạn hãy nhớ: Nếu các bạn gọi phương thức set() thì hãy nhớ gọi phương thức remove(), đặc biệt là khi chúng ta sử dụng thread pool với ExecutorService hoặc là web servers như Apache Tomcat.

Add Comment