欢迎光临散文网 会员登陆 & 注册

ThreadLocal错误示范

2022-04-13 10:26 作者:free-coder  | 我要投稿

1 接口返回对象封装到ThreadLocal

    服务接口返回的Response对象有仨字段code,msg和data,每次成功的返回都是code=0,msg=success,只修改data部分。想着要不就把Response对象封装到ThreadLocal中,每次从ThreadLocal去get,然后setData,然后return。

    这样做的话,服务如果有300个线程的池子,那就只需要300个Response对象,不用每次新请求来都重新new一遍啦,可以减少gc。看似很理想,实际上会出问题,服务常用的网络框架netty需要对return的这个Response对象序列化,序列化过程是扔到一个队列中来处理,是将对象引用扔过来,如果使用ThreadLocal,在return之后该线程结束,下一个新请求如果被该线程承接,就会set成新的data,这时候netty队列可能还没处理到这个对象,就会导致结果返回到client端之前就被篡改。

    所以不要对接口返回对象封装成ThreadLocal,就每次new就好啦。


2 线程池中的线程可以启动线程,并且CallerRun拒绝策略

    使用ThreadLocal有个很好的习惯就是在finally中remove,但是当使用ForkedJoinPool的时候或者线程池中线程可以从池子中拿新线程启动任务的时候,可能会出现空指针,这是怎么回事呢。

    池子中一个线程T1需要启动一个新的任务他就从池子中去拿,但是发现线程池满,就被拒绝了,然后策略是CallerRun,那就自己来阻塞式的执行这个新的任务。每个任务都是需要getThreadLocal最后removeThreadLocal。

    因为执行新任务的时候,在任务临终前remove掉了ThreadLocal,导致栈退上来之后,当前T1上下文ThreadLocal无了,继续往下执行就get不到了。

    所以使用线程池的时候,尽量避免池子中的线程可以创建新的线程。使用ForkedJoinPool的时候,自己要特别注意ThreadLocal的处理,可以在线程开始的地方先get出内容,防止后面get不到了。

ThreadLocal错误示范的评论 (共 条)

分享到微博请遵守国家法律