ThreadLocal使用详解(4大使用方式示例)

ThreadLocal使用详解(4大使用方式示例)-mikechen

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面试题总结》,后台回复架构,即可获取《阿里架构师进阶专题全部合集

评论交流
    说说你的看法