Java并发编程之threadLocal

Java并发编程之threadLocal完整攻略

ThreadLocal是Java提供的一种线程封闭机制,可以实现线程间数据隔离。在并发编程中,线程间数据共享往往是很麻烦的问题,而ThreadLocal则可以帮助我们方便地解决这一问题。

ThreadLocal基本概念

以简单的方式来描述ThreadLocal,就是一个类似于Map的存储结构。不同之处在于,Map中的key是任何对象,而ThreadLocal的key值必须是当前线程内的对象。ThreadLocal提供了get()和set()的方法,可以在当前线程内存储和获取任何对象。

ThreadLocal使用场景

  1. 事务管理

在一个事务中,可能存在多个并发的线程,而每个线程都会访问同一个Connection对象。为了保证线程安全,需要每个线程都持有自己的Connection,这时候就可以使用ThreadLocal来实现。

public class ConnectionManager {
    private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<>();

    public static Connection getConnection() throws SQLException {
        Connection conn = connectionHolder.get();
        if (conn == null) {
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
            connectionHolder.set(conn);
        }
        return conn;
    }

    public static void closeConnection() throws SQLException {
        Connection conn = connectionHolder.get();
        if (conn != null) {
            conn.close();
            connectionHolder.remove();
        }
    }
}

2.避免多个线程之间产生相互影响

多线程场景中,如果有多个线程需要同时操作同一个变量,那么ThreadLocal就可以派上用场。例如,每个线程需要一个单独的计数器,那么使用ThreadLocal可以非常方便地实现。

public class Counter {
    private static ThreadLocal<Integer> counterHolder = new ThreadLocal<Integer>() {
        protected Integer initialValue() {
            return 0;
        }
    };

    public static void increase() {
        counterHolder.set(counterHolder.get() + 1);
    }

    public static int getCount() {
        return counterHolder.get();
    }
}

ThreadLocal使用注意点

  1. 内存泄漏

在使用ThreadLocal时,需要注意内存泄漏问题。因为ThreadLocal会在每个线程内部创建一个Map,如果没有显式地调用remove()方法,就可能会造成内存泄漏。

  1. 并发问题

ThreadLocal本身并不是线程安全的,需要在多线程情况下进行操作时需要进行同步控制。

ThreadLocal总结

  • ThreadLocal提供了一种线程封闭机制,可以实现线程内的数据隔离。
  • ThreadLocal常用于需要线程安全且多线程并发访问的场景。
  • 在使用ThreadLocal时需要注意内存泄漏和并发问题。

参考文章:Java并发编程之ThreadLocal

示例说明

示例1:使用ThreadLocal实现每个线程中持有自己的DateFormat对象

在Java中,SimpleDateFormat是非线程安全的,因此不能再多线程环境中直接使用。但是使用ThreadLocal可以在每个线程中持有自己的SimpleDateFormat实例,从而保证线程安全。

public class SimpleDateFormatPattern {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    DateFormat dateFormat = SafeSimpleDateFormat.get();
                    System.out.println("Thread: " + Thread.currentThread().getName() + ", DateFormat-Hashcode: " + dateFormat.hashCode());
                }
            };
            executorService.execute(runnable);
        }
        executorService.shutdown();
    }
}

class SafeSimpleDateFormat {
    private static final ThreadLocal<DateFormat> sdfHolder = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"));

    private SafeSimpleDateFormat() {
    }

    public static DateFormat get() {
        return sdfHolder.get();
    }
}

示例2:使用ThreadLocal解决DAO对象中的connection问题

在DAO数据访问对象中,要保证每个方法都能获取到Connection对象,但是这个Connection对象又需要自己手动的关闭,使用ThreadLocal将Connection对象和线程绑定,线程结束时自动关闭Connection,在线程安全的基础上提高效率。

public abstract class AbstractContext {
    private static final ThreadLocal<Connection> CONTEXT_HOLDER = ThreadLocal.withInitial(() -> {
        try {
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
            connection.setAutoCommit(false);
            return connection;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    });

    protected Connection getConnection() {
        return CONTEXT_HOLDER.get();
    }

    public void push() {
        try {
            Connection connection = getConnection();
            connection.commit();
            connection.close();
            CONTEXT_HOLDER.remove();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    public void pull() {
        try {
            Connection connection = getConnection();
            connection.rollback();
            connection.close();
            CONTEXT_HOLDER.remove();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java并发编程之threadLocal - Python技术站

(0)
上一篇 2023年5月16日
下一篇 2023年5月16日

相关文章

  • Java让多线程按顺序执行的几种方法

    Java中多线程是独立运行的,并发执行,遵循自己的时间表。但是,有时候需要按照特定的顺序来执行多个线程,以便其运行方式与编程要求相适应。本文将介绍Java让多线程按顺序执行的几种方法。 方法1.依靠join()方法 在Java中,线程可以使用join()方法等待另一个线程的完成,直到当前线程已经结束执行或等到timeout毫秒。这个方法只能在共享同一个对象的…

    多线程 2023年5月17日
    00
  • Java并发编程之Fork/Join框架的理解

    Java并发编程之Fork/Join框架的理解 什么是Fork/Join框架? Fork/Join框架是Java7引入的一种并行执行任务的机制,它通过将一个大任务分割成若干个小任务来并行地执行这些小任务,最终把这些小任务的结果合并起来得到大任务的结果。这种方式可以充分利用多核处理器的性能,加速任务执行速度,是一种高效的多线程编程方式。 Fork/Join框架…

    多线程 2023年5月16日
    00
  • Java多线程并发编程(互斥锁Reentrant Lock)

    Java多线程并发编程(互斥锁Reentrant Lock)攻略 概述 在Java多线程编程中,为了保证多个线程并发执行时的安全性,我们需要使用同步控制。在Java中,synchronized关键字可以实现同步控制,但是它存在一些不足之处,比如它的锁只能是内置锁,无法进行灵活的控制和管理等。 为了解决这些问题,Java提供了一个更加灵活、功能更为强大的锁机制…

    多线程 2023年5月16日
    00
  • Redis高并发情况下并发扣减库存项目实战

    Redis高并发情况下并发扣减库存项目实战 项目背景 很多电商平台在购物高峰期会面临商品库存不足的问题,而库存紧张问题不但要求电商平台提高库存的数量,也要求电商平台优化库存的流程,实现高效扣减库存。 本项目利用Redis实现库存扣减,具体做法是:每次库存变动可以作为一个事务放到Redis的事务队列中,通过WATCH命令加锁机制,避免并发扣减库存冲突。 项目实…

    多线程 2023年5月16日
    00
  • SpringCloud LoadBalancerClient 负载均衡原理解析

    SpringCloud LoadBalancerClient 负载均衡原理解析 什么是负载均衡? 负载均衡(Load Balancing)是指将工作请求分担到多个计算资源上进行处理,以达到最优化的资源利用、最大化的吞吐量、最小化响应时间、避免单点故障等目的。 传统的负载均衡方式有硬件负载均衡和软件负载均衡,但这些方式都需要使用专门的设备或者软件,且较为昂贵。…

    多线程 2023年5月17日
    00
  • php curl批处理实现可控并发异步操作示例

    下面是“php curl批处理实现可控并发异步操作示例”的完整攻略。 1. 准备工作 在开始之前,需要确保系统已经安装了curl扩展。可以通过以下命令来检查: php -m | grep curl 如果输出了curl,说明扩展已经安装成功。 2. 单个请求示例 首先来看一个简单的单个请求示例。代码如下: // 初始化curl $ch = curl_init(…

    多线程 2023年5月16日
    00
  • C语言由浅入深讲解线程的定义

    C语言线程定义攻略 什么是线程 线程是一种执行路径,是进程中的一个执行流程。一个进程可以拥有多个线程,每个线程都可以独立执行,但是它们都共享相同的资源。 线程的优势 线程可以极大的提高程序的运行效率。当程序的某部分需要长时间运行时,通过创建线程可以使得该部分程序有多个执行流程,让每个线程独立的运行。这样就能提高程序运行效率,减少用户等待时间,提高用户体验。 …

    多线程 2023年5月16日
    00
  • Node.js 多线程完全指南总结

    Node.js 多线程完全指南总结 简介 Node.js是一种事件驱动的、非阻塞式I/O的JavaScript运行时环境,通常用于服务器端的编程应用。虽然Node.js主要是单线程的,但是它是支持多线程操作的。本文将详细讲解Node.js多线程的概念和指南,并附上一些示例说明。 如何创建多线程 Node.js多线程最常用的方式是使用cluster模块和chi…

    多线程 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部