
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
mikechen睿哥,10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!