Java多线程编程涉及ThreadLocal的使用,通过ThreadLocal使用解决线程同步,主要包含4种ThreadLocal的使用@mikechen
1.全局变量的线程安全性
ThreadLocal类是Java中的一个线程本地变量类,每个线程都可以独立地修改自己的线程本地变量副本,而不会影响其他线程的副本。
如下所示:
public class MyRunnable implements Runnable { private ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(); @Override public void run() { threadLocal.set((int) (Math.random() * 100D)); try { Thread.sleep(2000); } catch (InterruptedException e) { } System.out.println("ThreadLocal值:" + threadLocal.get()); } } public class ThreadLocalExample { public static void main(String[] args){ MyRunnable sharedRunnableInstance = new MyRunnable(); Thread thread1 = new Thread(sharedRunnableInstance); Thread thread2 = new Thread(sharedRunnableInstance); thread1.start(); thread2.start(); try { thread1.join(); // 等待线程1结束 thread2.join(); // 等待线程2结束 } catch (InterruptedException e) { e.printStackTrace(); } } }
2.Web应用中的用户信息
在Web应用中每个请求都由一个线程处理,可以使用ThreadLocal来存储用户信息,这样就可以在多个方法之间共享用户信息,而又不必担心线程安全问题。
如下所示:
public class UserContext { private static final ThreadLocal<User> userThreadLocal = new ThreadLocal<>(); public static User getCurrentUser() { return userThreadLocal.get(); } public static void setCurrentUser(User user) { userThreadLocal.set(user); } public static void clear() { userThreadLocal.remove(); } } public class UserService { public void login(String username, String password) { // 验证用户名密码 User user = new User(username, password); UserContext.setCurrentUser(user); } public void logout() { UserContext.clear(); } public void doSomething() { User user = UserContext.getCurrentUser(); // 根据用户信息做一些操作 } }
3.数据库连接
在多线程环境下,数据库连接是共享资源,需要避免多个线程之间互相干扰。
可以使用ThreadLocal来存储每个线程的数据库连接,从而保证每个线程都有自己的连接,避免多个线程之间互相干扰。
如下所示:
public class DBUtil { private static final ThreadLocal<Connection> connectionThreadLocal = new ThreadLocal<>(); public static Connection getConnection() throws SQLException { Connection connection = connectionThreadLocal.get(); if (connection == null) { connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "password"); connectionThreadLocal.set(connection); } return connection; } public static void closeConnection() throws SQLException { Connection connection = connectionThreadLocal.get(); if (connection != null) { connection.close(); connectionThreadLocal.remove(); } } } public class UserService { public void doSomething() throws SQLException { Connection connection = DBUtil.getConnection(); // 使用连接执行一些操作 DBUtil.closeConnection(); } }
4.日期格式化器
在Java中SimpleDateFormat是线程不安全的,因此在多线程环境下需要避免共享SimpleDateFormat实例。
可以使用ThreadLocal来存储每个线程的SimpleDateFormat实例,这样就可以避免线程安全问题。
如下所示:
public class DateFormatter { private static final ThreadLocal<SimpleDateFormat> dateFormatThreadLocal = new ThreadLocal<SimpleDateFormat>() { @Override protected SimpleDateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); } }; public static String formatDate(Date date) { return dateFormatThreadLocal.get().format(date); } }
上就是4种ThreadLocal的使用详解,更多ThreadLocal,请查看:史上最强ThreadLocal详解(图文全面解析)
陈睿mikechen
10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!
后台回复【面试】即可获取《史上最全阿里Java面试题总结》,后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》