ThreadLocal

文章详细对比了在每个线程中创建对象与使用ThreadLocal的差异,解释了ThreadLocal如何解决线程安全问题并减少内存占用。通过示例代码展示了ThreadLocal在初始化时返回新对象的重要性,强调了线程复用在节省资源中的作用。同时指出,不正确使用initialValue方法可能导致线程安全问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于概念和使用就不多介绍了,自行百度

这里主要针对许多博客都没解释清楚的点进行说明,也是我曾疑惑的点。

(1)在每个线程中创建一个对象和在每次任务执行时创建对象的区别?

(2)在继承ThreadLocal对象重写initialValue方法时是否需要重新new 对象,此时的new 对象又是什么意思呢?

先上代码:

//未使用ThreadLocal以及锁,而是每个线程在执行任务时都会去新建一个对象
public  class HHHH {
     public static void main(String[] args) {
         ExecutorService executorService = Executors.newFixedThreadPool(4);
         for (int i = 1; i <=100; i++) {
             int finalI = i;
             executorService.execute(new Runnable() {
                 @Override
                 public void run() {
                     System.out.println(new HHHH().date(finalI));
                 }
             });
         }
     }
     public  String  date(int seconds){
         Date date = new Date(1000*seconds);
         SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd:hh:mm:ss");
         return  simpleDateFormat.format(date);
     }
}
//使用ThreadLocal,每个线程存放一个ThreadLocal对象
public  class HHHH {
    public  static   ExecutorService executorService= Executors.newFixedThreadPool(4);
    public static void main(String[] args) {
        for (int i = 1; i <=1000; i++) {
            int finalI = i;
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(new HHHH().date(finalI));
                }
            });
        }
        executorService.shutdown();
    }
    public  String  date(int seconds){
        Date date = new Date(1000*seconds);
        SimpleDateFormat simpleDateFormat = ThreadSafe.dateFormatThreadLocal.get();
        return simpleDateFormat.format(date);
    }
}
class ThreadSafe {
    public  static ThreadLocal<SimpleDateFormat>  dateFormatThreadLocal= new ThreadLocal<SimpleDateFormat>(){
         SimpleDateFormat   sim = new  SimpleDateFormat("yyyy-MM-dd:hh:mm:ss");
        //若执行get方法时,没有赋值,此时会执行该方法,返回该方法的值,并且会在当前线程的ThreadLocalMap中存放值是该value的键值对。
        @Override
        protected SimpleDateFormat  initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd:hh:mm:ss");//每个线程返回一个对象,不会出现线程安全问题
           // return  sim ; //此时才是不占内存的,因为在每个线程的threadLocalMap中存放的都是该对象的引用,但是你会发现还是出现了线程安全问题,因为我们操作的是一个对象嘛
        }
    };
}

仔细阅读代码,你会有很多发现。

上结论:

(1)在方法中创建对象,则每执行一次方法都会创建一个对象,比如代码中写了1000次执行方法,则创建了1000SimpleDateFormat个对象,不存在线程安全问题,但极大的占用堆内存空间;

(2)使用ThreadLocal,在每个线程中创建一个对象,其实主要是利用到了线程池的线程复用,即一个线程会执行n个任务,比如代码中只创建了一个有4个线程的线程池,那么这4个线程其实创建了4个SimpleDateFormat对象,而线程与线程之间的对象不同保证了线程安全,但又减少了占用的内存空间

(3)在实现initialValue方法时,创建新对象,是返回给每一个线程使用的;若选择返回对象引用,那么所有的线程操作的都是同一个对象,仍然存在线程安全问题。

(4)补充一下initialValue方法的逻辑,方便更容易理解上一点。在执行get方法时,会去判断当前线程中是否有threadlocalMap对象,若有则会取值返回,若没有,则会执行setInitialValue方法,该方法会去执行initialValue方法获取值,并且!会将该键值对存到Map中。那么也就是,每一个线程肯定只会执行一次setInitialValue方法,即只会执行一次initialValue方法。

综上所述:使用ThreadLocal避免内存的消耗,其实还是得益于线程复用。

欢迎留言讨论哦~期待你的关注

当使用`connect / as sysdba`命令以`sysdba`身份连接到Oracle数据库时,如果出现ORA-01031: insufficient privileges错误,这通常意味着当前用户没有足够的权限来执行该操作。 解决这个问题的方法有几种: 1. 确保你使用的是正确的用户名和密码。`sysdba`权限是一种特殊权限,只有具有特定权限的用户才能以`sysdba`身份连接到数据库。请确保你使用的用户名和密码是正确的,并且具有`sysdba`权限。 2. 确认你的操作系统用户具有连接到数据库的权限。在某些情况下,你可能需要确保你的操作系统用户具有与Oracle数据库实例关联的正确操作系统权限。请检查你的操作系统用户是否具有适当的权限,并尝试使用正确的操作系统用户来连接到数据库。 3. 检查用户是否具有必要的权限。即使以`sysdba`身份连接到数据库,你仍然需要确保你连接的用户具有执行所需操作的权限。请检查用户是否具有必要的权限,例如在执行特定的存储过程或创建表时。 4. 检查数据库参数设置。有时,ORA-01031错误可以由数据库参数设置导致。特别是,你可能需要检查`REMOTE_LOGIN_PASSWORDFILE`参数的设置。如果该参数设置为NONE,连接到数据库时不会要求提供密码文件。但如果设置为EXCLUSIVE或SHARED,那么连接到数据库时需要提供正确的密码文件。 5. 运行`orapwd`命令重新创建密码文件。如果出现ORA-01031错误,你可以尝试使用`orapwd`命令重新创建密码文件。这将确保存在正确的密码文件,并可能解决权限问题。 请根据具体情况尝试上述方法,并确保你具有足够的权限来执行所需的操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [ora-01031禁止操作系统集成的身份验证方式](https://download.youkuaiyun.com/download/john_lewis/5196130)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [ORA-01031 :insufficient privileges](https://blog.youkuaiyun.com/weixin_36214833/article/details/117597432)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [执行sqlplus / as sysdba报错ORA-01031: insufficient privileges](https://blog.youkuaiyun.com/u014710633/article/details/122927908)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值