zoukankan      html  css  js  c++  java
  • ThreadLocal 和Synchronized

        并发都用到, 两个都是解决了线程并发问题,区别呢?

    Synchronized  同步机制, 共有变量被多个线程使用,会出现线程不安全,所以,加锁,锁机制很多种,例如Synchronized, lock 锁, 阻塞队列。以时间换空间, 某一个线程拿到锁, 先进去, 其他线程, 等着吧~

    ThreadLocal ,当多个线程使用一个对象, 以空间换时间, 创建不同的变量副本。大家不要抢, 每个人都有!首先这个对象是全局变量。

    ThreadLocal 保证了线程的隔离性 ,一个经典的例子是 SimpleDateFormat 线程不安全问题, 这个时间格式化 工具类我们使用频率非常大 。

    Synchronized使用场景:比如1000 张火车票, 每个线程操作, 必须保证每个窗口卖 不同 的火车票, 保证座位不相同! 这1000 张票是原子性的。

    ThreadLocal使用场景:举例: spring security管理权限  , 每个用户用户名,密码验证登录会存在 Authentication中, 包括用户名密码, 是否被锁定, 是否过期,等很多消息, 这是一个对象, 当用户登录之后, 使用这个系统, 比如查看自己的订单,自己的购物车,自己的余额 ,这里Authentication 就是全局变量,如果多个用户登录,这个对象肯定会被改变, 简单的方法是 每一个用户 授权登录后, 都生成一个全局变量对象, 但是1000 万 个用户呢,系统会不会垮掉?肯定是!

     这就是线程并发非同步的另一种领域,数据隔离,保证每个用户有各自的数据, 用同步加锁是不能解决的。

     所以可以创建一个threadLocal , 看看  spring security 的源码:

    /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *     http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.security.core.context;
    
    import org.springframework.util.Assert;
    
    /**
     * A <code>ThreadLocal</code>-based implementation of
     * {@link SecurityContextHolderStrategy}.
     *
     * @author Ben Alex
     *
     * @see java.lang.ThreadLocal
     * @see org.springframework.security.core.context.web.SecurityContextPersistenceFilter
     */
    final class ThreadLocalSecurityContextHolderStrategy implements
            SecurityContextHolderStrategy {
        // ~ Static fields/initializers
        // =====================================================================================
           //核心在这里 , 这里创建 一个 threadLocal 的 SecurityContext
        private static final ThreadLocal<SecurityContext> contextHolder = new ThreadLocal<SecurityContext>();
    
        // ~ Methods
        // ========================================================================================================
    
        public void clearContext() {
            contextHolder.remove();
        }
    
        public SecurityContext getContext() {
            SecurityContext ctx = contextHolder.get();
    
            if (ctx == null) {
                ctx = createEmptyContext();
                contextHolder.set(ctx);
            }
    
            return ctx;
        }
    
        public void setContext(SecurityContext context) {
            Assert.notNull(context, "Only non-null SecurityContext instances are permitted");
            contextHolder.set(context);
        }
    
        public SecurityContext createEmptyContext() {
            return new SecurityContextImpl();
        }
    }

    再看看线程全局变量怎么被设置进去

           //这个是登录方法, 用户名密码登录
    public void login(String username, String password) throws ServletException { if (isAuthenticated()) { throw new ServletException("Cannot perform login for '" + username + "' already authenticated as '" + getRemoteUser() + "'"); } AuthenticationManager authManager = authenticationManager; if (authManager == null) { logger.debug("authenticationManager is null, so allowing original HttpServletRequest to handle login"); super.login(username, password); return; } Authentication authentication; try {
    //这里去数据库验证, 用户名错误?用户名过期?用户被锁定?用户什么角色 authentication
    = authManager .authenticate(new UsernamePasswordAuthenticationToken(username, password)); } catch (AuthenticationException loginFailed) { SecurityContextHolder.clearContext(); throw new ServletException(loginFailed.getMessage(), loginFailed); }
    //这里全是全局变量 设置进去 SecurityContextHolder.getContext().setAuthentication(authentication); }

    好了, 一个验证通过了, 并被设置到threadLocal ,

    现在用户删除订单

        @RequestMapping(value = "/deleteId", method = RequestMethod.POST)
        @ResponseBody
        public JSONObject deleteId(@RequestParam("strJson")String json) {
    //SecurityContextHolder 是一个全局变量, 直接在方法里面获取 Authentication auth
    = SecurityContextHolder.getContext() .getAuthentication(); Integer role=-1; Object pinciba = auth.getPrincipal(); if (pinciba instanceof Customer) { role =((Customer) pinciba).getRole(); } if(role==2){ //管理员删除 }else{ //非管理员不能删除 } JSONObject jsons = new JSONObject(); System.out.println(json); return jsons; }

    threadlocal 很强大, 一种弱引用。我们知道Java有四中对象:

       从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期。这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用。

     threadLocal 就是一种弱引用, 当某个用户很长时间没有登录, 而 其他用户需要threadLocal 添加一个自己的 变量, 就会回收没有使用了, 实现了线程数据隔离吧。

  • 相关阅读:
    centos,ubuntu下安装zabbix遇到的问题
    代理环境下使用 ADDAPTREPOSITORY 添加 PPA 软件源
    Linux文件系统挂载管理
    Log4j配置详解
    myeclipse快捷键
    Linux用户基础(用户和组)
    C语言I博客作业07
    C语言I博客作业02
    C语言I博客作业08
    C语言I博客作业04
  • 原文地址:https://www.cnblogs.com/zgghb/p/6070035.html
Copyright © 2011-2022 走看看