精华内容
下载资源
问答
  • 前端与后端交互,说得直接一点,就是体现在network中,而状态我们比较关注的个点,那么我们来总结一下http状态码,都表示什么意思?http状态码分为五类型:1**,2**,3**,4**,5**。 分类 分类描述 ...

    前端与后端交互,说得直接一点,也就是体现在network中,而状态码是我们比较关注的一个点,那么我们来总结一下http状态码,都表示什么意思?http状态码分为五种类型:1**,2**,3**,4**,5**。

    分类 分类描述
    1** 信息,服务器收到请求,需要请求者继续执行操作
    2** 成功,操作被成功接收并处理
    3** 重定向,需要进一步的操作以完成请求
    4** 客户端错误,请求包含语法错误或无法完成请求
    5** 服务器错误,服务器在处理请求的过程中发生了错误

     以下是具体的含义:

    状态码 状态码英文名称 中文描述
    100 Continue 继续。客户端应继续其请求
    101 Switching Protocols 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议
     
    200 OK 请求成功。一般用于GET与POST请求
    201 Created 已创建。成功请求并创建了新的资源
    202 Accepted 已接受。已经接受请求,但未处理完成
    203 Non-Authoritative Information 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本
    204 No Content 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档
    205 Reset Content 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域
    206 Partial Content 部分内容。服务器成功处理了部分GET请求
     
    300 Multiple Choices 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择
    301 Moved Permanently 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
    302 Found 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
    303 See Other 查看其它地址。与301类似。使用GET和POST请求查看
    304 Not Modified 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
    305 Use Proxy 使用代理。所请求的资源必须通过代理访问
    306 Unused 已经被废弃的HTTP状态码
    307 Temporary Redirect 临时重定向。与302类似。使用GET请求重定向
     
    400 Bad Request 客户端请求的语法错误,服务器无法理解
    401 Unauthorized 请求要求用户的身份认证
    402 Payment Required 保留,将来使用
    403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求
    404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
    405 Method Not Allowed 客户端请求中的方法被禁止
    406 Not Acceptable 服务器无法根据客户端请求的内容特性完成请求
    407 Proxy Authentication Required 请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权
    408 Request Time-out 服务器等待客户端发送的请求时间过长,超时
    409 Conflict 服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突
    410 Gone 客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置
    411 Length Required 服务器无法处理客户端发送的不带Content-Length的请求信息
    412 Precondition Failed 客户端请求信息的先决条件错误
    413 Request Entity Too Large 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息
    414 Request-URI Too Large 请求的URI过长(URI通常为网址),服务器无法处理
    415 Unsupported Media Type 服务器无法处理请求附带的媒体格式
    416 Requested range not satisfiable 客户端请求的范围无效
    417 Expectation Failed 服务器无法满足Expect的请求头信息
     
    500 Internal Server Error 服务器内部错误,无法完成请求
    501 Not Implemented 服务器不支持请求的功能,无法完成请求
    502 Bad Gateway 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
    503 Service Unavailable 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
    504 Gateway Time-out 充当网关或代理的服务器,未及时从远端服务器获取请求
    505 HTTP Version not supported 服务器不支持请求的HTTP协议的版本,无法完成处理

    以上是全部的HTTP状态码。请牢记。。。 

    展开全文
  • 、什么线程安全性 在线程安全性中,最核心的就是正确性。 正确性含义:某个类的行为与其规范完全一致。 线程安全: 当多个线程...比如,Servlet框架中的类StatelessFactorizer状态的:它既不包含任何域,不包

    一、什么是线程安全性

       在线程安全性中,最核心的就是正确性。
    正确性含义:某个类的行为与其规范完全一致。

       线程安全: 当多个线程访问某个类时,不管运行数时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。

    注意:在线程安全类中封装了必要的同步机制,因此客户端无须进一步采取同步措施。

       无状态对象一定是线程安全的。比如,Servlet框架中的类StatelessFactorizer是无状态的:它既不包含任何域,也不包含任何对其他类中域的引用。这个类计算过程中的临时状态仅存于线程栈上的局部变量中,并且只能由正在执行的线程访问。
       访问一个StatelessFactorizer的线程不会影响另一个访问同一个StatelessFactorizer的线程的计算结果,因为这两个线程并没有共享状态,就像它们在访问不同的实例。由于线程访问无状态对象不会影响其他线程中操作的正确性,因此无状态对象是线程安全的。

       大多数Servlet都是无状态的,只有当Servlet在处理请求时需要保存一些信息,线程安全性才会成为一个问题。

    二、原子性

    举例:没有同步的情况下统计给Value赋值的次数。

    public class Sequence {
        private int Value;
    
        public int getValue(){
            return Value;
        }
        
        public void fz(boolean p){
            if(p){
                ++Value;
            }
        }
    }
    

       这个类在单线程能够正常执行。但在多线程中很可能会丢失一些更新操作。虽然递增操作++Value是一种紧凑的语法,使其看上去只是一个操作,但这个操作并非是原子的,因而他并不会作为一个不可分割的操作来执行。实际上,它包含了三种操作,读取count的值,将值加1,然后将值写入count。这是一个“读取-修改-写入”的操作序列,并且结果依赖之前的状态。

       假设两个线程在没有同步的情况下对它进行操作,很可能发生这样的情况:此时Value的值为6,A线程正在修改Value的值,而B线程在A线程修改Value操作开始后但没有执行完的时间段调用getValue方法,由于此时A线程还没有来得及将修改的新的Value值写回,B线程就读取的修改前Value的值,即6,而实际上B应该读取Value的值为7。

       在并发编程中,这种由于不恰当的执行时序而出现不正确的结果是一种非常重要的情况,它由一个正式的名字:竞态条件

    三、竞态条件阐述

       竞态条件中的一类是“先检查后执行”:首先观察到某个条件为真,然后根据这个观察结果采取相应的动作,但事实上,在你观察到这个结果到你开始执行相应的操作之间,观察结果可能变得无效,从而导致各种问题(未预期的异常、数据被覆盖、文件被破坏等)。可以举个例子,假设你和朋友约定10点在奶茶店见面,你已经到了并且等待了10分钟,当你判断朋友鸽你并且向前门走出时,你的朋友刚好出现在后门,(你此时得到朋友鸽你的信息就变得无效了)此后你得到错误信息 朋友爽约,而其实朋友是来了的,然后就会导致你和朋友的矛盾。

       要避免竞态条件,就必须在某个线程修改该变量时,通过某种方式防止其他线程使用这个变量,从而确保其他线程只能在修改完成之前或之后读取和修改状态,而不是在修改状态的过程中。

       假定有两个操作A和B,如果从执行A的线程来看,当另一个线程执行B时,要么将B全部执行完,要么完全不执行B,那么A和B对彼此来说是原子的。

       为了确保线程安全“先检查后执行”和读取-修改-写入操作必须是原子的。我们将“先检查后执行”和读取-修改-写入统称为复合操作。

        在java.util.concurrent.atomic包中包含了一些原子变量类,用于实现在数值和对象引用上的原子状态转换。通过用AtomicLong来代替long类型的计数器,能够确保所有对计数器状态的访问操作都是原子的。

       AtomicLong是一种替代long类型整数的线程安全类,类似地,AtomicReference是一种替代对象引用的线程安全类。
       要保证状态的一致性,就需要在单个原子操作中更新所有相关的状态变量。

    四、内置锁

       Java提供了一种内置的锁机制来支持原子性:同步代码块(Synchronized Block)同步代码块包括两部分:一个作为锁的对象引用,一个作为有这个锁保护的代码块。

       每个Java对象都可以用做一个实现同步的锁,这些锁被称为内置锁或监视器锁。线程在进入同步代码块之前会自动获得锁,并且在退出同步代码块时自动释放锁,而无论通过正常的控制路径退出,还是通过代码块中抛异常退出。获得内置锁的唯一途径就是进入由这个锁保护的同步代码块或方法。

       Java的内置锁相当于一种互斥体(或互斥锁),这意味着最多只有一个线程能持有这种锁。当线程A尝试获取由线程B持有的锁时,线程A必须等待或者阻塞,直到线程B获得这个锁。如果线程B永远不释放锁,那么A也将永远地等待下去。

       由于每次只能有一个线程执行内置锁保护的代码块,因此,由这个锁保护的同步代码块会以原子方式执行,多个线程在执行该代码块时也不会相互干扰。并发环境中的原子性与事务应用程序中的原子性有着相同的含义。一组语句作为一个不可分割的单元被执行。任何一个执行同步代码块的线程,都不可能看到有其他线程正在执行同一个锁保护的同步代码块。

    五、重入

       当某个线程请求一个由其他线程持有的锁时,发出请求的线程就会阻塞。在程序运行时会发生这样一种情况:

    package xiancheng;
    
    public class Widget {
        public synchronized void doSomething(){
            //...
        }
        
        public class LoggingWidget extends Widget{
            public synchronized void doSomething(){
                System.out.println(toString()+":calling dosomething");
                super.doSomething();
            }
        }
    }
    

       由于每个dosomething方法在执行前都会获取Widget上的锁。然而,如果内置锁不是可重入的,那么在调用super.doSomething时将无法获得Widget上的锁,因为这个锁已经被持有,从而线程将永远停顿下去,等待一个永远无法获得的锁。重入则避免了这种死锁情况的发生。

       重入的一种实现方法是,为每个锁关联一个获取计数值和一个所有者线程。当计数值为0时,这个锁就被认为是没有被任何线程持有。当线程请求一个未被持有的锁时,JVM将记下锁的持有者,并且将获取计数值置为1.如果同一个线程再次获取这个锁,计数值将递增,而当线程退出同步代码块时,计数器会相应的递减。当计数值为0时,这个锁将被释放。

    六、用锁来保护状态

       对于可能被多个线程同时访问的可变状态变量,在访问它时都需要持有同一个锁,在这种情况下,我们称这个变量是由这个锁保护的。

       1.每个共享的和可变的变量都应该只由一个锁来保护,从而使维护人员知道是哪一个锁。

       2.对于每个包含多个变量的不变性条件,其中涉及的所有变量都需要由同一个锁来保护。

       3.如果只是将每个方法都作为同步方法,例如Vector,那么并不足以确保Vector上复合操作都是原子的:

    if(!vector.contains(element))
    	vector.add(element);
    

       虽然contains和add等方法都是原子方法,但在上面这个“如果不存在则添加”的操作中仍然存在竞态条件。虽然synchronized方法可以确保单个操作的原子性,但如果要把多个操作合并为一个复合操作,还需要额外的加锁机制。此外,将每个方法都作为同步方法还可能会导致活跃性问题或性能问题。

    七、活跃性与性能

       使用两种不同的同步机制不仅会带来混乱,也不会在性能或者安全性上带来热河好处,因此在这里不使用原子变量。

       无论是执行计算密集的操作,还是在执行某个可能阻塞的操作,如果持有锁的时间过长,那么都会带来活跃性问题或性能问题。

       当执行 时间较长的计算或者可能无法快速完成的操作时(例如,网络I/O或控制台I/O),一定不要持有锁。

    展开全文
  • 非严格意义上讲,一个...java的首选的同步机制使用synchronized关键字,该关键字提供一种排他性的锁。当然先同步还包括了volatile变量,显式锁,以及原子变量。   避免风险的三条法则: Don

    非严格意义上讲,一个对象的状态(state)就是它的数据。何为数据,比如实例的或者静态的域。当然对象的state也可以包含其他。

     

    并发条件下的不安全因素始于这些状态。这些状态可能被诸多不同线程修改从而造成不一致的风险。避免风险就要使得这些并发的线程同步协作。java的首选的同步机制是使用synchronized关键字,该关键字提供一种排他性的锁。当然是先同步还包括了volatile变量,显式锁,以及原子变量。

     

    避免风险的三条法则:

    • Don't share the state variable across threads;

    • Make the state variable immutable; or

    • Use synchronization whenever accessing the state variable。

       

      最便捷的方法莫过于使对象“无状态化”。

      Stateless objects are always thread-safe.


       

    展开全文
  • 线程安全和对象共享

    2017-04-19 19:55:53
    1.定义:当多个线程访问某个类时,不管运行时环境采用何调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协调,这个类都能表现出正确的行为,那么就称这个类线程安全类。...

    一、线程安全类
    1.定义:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协调,这个类都能表现出正确的行为,那么就称这个类是线程安全类。

    2.确保线程安全的方法
    (1)无状态对象:不包含任何域,也不包含任何对其他类中的域的引用。计算过程中的临时状态仅存在于线程栈上的局部变量中,并且只能由正在执行的线程访问。

    public class StatelessFactorizer implements Servlets{
        public void service(ServletRequest req,ServletResponse resp){
            BigInteger i = extractFromRequest(req);
            BigInteger[] factors = factor(i);
            encodeIntoResponse(resp,factors);
        } 
    }

    (2)不可变对象:不可变对象需要满足以下的条件:对象创建后其状态就不可以修改;对象的所有域都是 final 类型;对象是正确创建的(在对象创建期间,没有this引用逸出)。

    /**
     * 对数值及其因数分解结果进行缓存的不变容器类
     * @author shier
     *
     */
    public class OneValueCache {
        private final BigInteger lastNumber;
        private final BigInteger[] lastFactors;
    
        public OneValueCache(BigInteger i,BigInteger[] factors) {
            lastNumber = i;
            lastFactors = Arrays.copyOf(factors, factors.length);
        }
    
        public BigInteger[] getFactors(BigInteger i){
            if(lastNumber == null && !lastNumber.equals(i)){
                return null;
            }else{
                return Arrays.copyOf(lastFactors, lastFactors.length);
            }
        }
    }
    

    (3)原子变量
    原子操作:指对于访问同一个状态的所有操作(包括该操作本身)来说,这个方式是以一个原子方式执行的操作。

    原子变量:自身是线程安全的,但是如果一个不变约束涉及多个变量时,变量间不是彼此独立的,无论这些变量是否是原子变量都不
    能确保线程安全,而需要在同一个原子操作中更新这些相互关联的状态变量才能确保线程安全。
    JDK的Java.util.concurrent.atomic包中包括了原子变量类,这些类用来实现数字和对象引用的原子状态转换。
    
    /**
     * 使用AtomicLong类型的变量来统计已处理请求的数量
     * 当在无状态的类中添加一个状态时,如果状态完全有线程安全的对象来管理,那么这个类仍然是线程安全的
     */
    public class CountingFactorizer {
    
        private final AtomicLong count = new AtomicLong(0);
    
        public long getCount(){
            return count.get();
        }
    
        public void service(ServletRequest req,ServletResponse resp){
            BigInteger i = extractFromRequest(req);
            BigInteger[] factors = factor(i);
            count.incrementAndGet();
            encodeIntoResponse(resp,factors);
        }
    }
    

    (4)正确使用同步加锁机制:例如synchronized内置锁、ReentrantLock显示锁以及validate轻量级锁等。

    二、竞态条件:指多个线程或者进程在读写一个共享数据时结果依赖于它们指令执行的相对时序,即要想得到正确的结果,要依赖于幸运的时序。最常见的竞争条件是“检查再运行”,使用一个潜在的过期值作为决定下一步操作的依据。

    /**
     * 延迟初始化加载实例
     * @author shier
     *
     */
    public class LazyInitRace {
        private Object inatance = null;
    
        public Object getInstance(){
            if(inatance == null){
                inatance = new Object();
            }
            return inatance;
        }
    }

    三、加锁机制
    1.内置锁
    Java提供了强制原子性的内置锁机制:synchronized块。
    一个synchronized块有两部分:锁对象引用,以及该锁保护的代码块。
    synchronized方法的锁是该方法所在的对象本身,静态的synchronized方法的锁是从Class对象上获取的锁。内部锁的特性如下:
    (1).自动获得和释放:
    每个java对象都可以隐式地扮演一个用于同步的锁的角色,这些内置的锁被称为内部锁或监视器锁,执行线程进入synchronized块之前自动获得锁,而无论是正常退出还是抛出异常,线程都会自动释放锁。因此获得内部锁的唯一途径是进入这个内部锁保护的同步块或方法。
    (2).互斥性:
    内部锁在java中扮演了互斥锁的角色,即至多只有一个线程可以拥有锁,没有获取到锁的线程只能等待或阻塞直到锁被释放,因此同步块可以线程安全地原子执行。
    (3).可重入性:
    可重入是指对于同一个线程,它可以重新获得已有它占用的锁。
    可重入性意味着锁的请求是基于”每线程”而不是基于”每调用”,它是通过为锁关联一个请求计数器和一个占有它的线程来实现。
    可重入性方便了锁行为的封装,简化了面向对象并发代码的开发,可以防止类继承引起的死锁,例子如下:

    public class Widget {  
        public synchronized void doSomething(){  
            ......  
        }  
    }  
    
    public class LoggingWidget extends Widget {  
        public synchronized void doSomething(){  
            System.out.println(toString() + “: calling doSomething”);  
            super.doSomething();  
        }  
    }  

    子类LoggingWidget覆盖了父类Widget中synchronized类型的doSomething方法,并调用了父类的中的同步方法,因此子类LoggingWidget和父类Widget在调用doSomething方法之前都会先获取Widget的锁,若内部锁没有可重入性,则super.doSomething的调用就会因为无法获得锁而被死锁。

    四、内存可见性
    当一个线程修改了对象状态后,其他线程能够看到发生的状态变化。
    1.指令重排序:在没有同步的情况下,编译期、处理器以及运行时等都可能对操作的执行顺序进行一些意想不到的调整。在缺乏足够同步的多线程程序中,要相对内存操作的执行顺序进行判断,几乎无法得到正确结论。

    2.保证多线程的内存可见性的方式
    (1)锁:锁不仅仅是关于同步与互斥的的,也是关于内存可见性的,为了保证所有线程都能看到共享的、可变变量的最新值,读取和写入线程必须使用公共的锁进行同步,锁确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的 。

    (2)validate变量:volatile是一种弱形式的同步, volatile确保对一个变量的更新以可预见的方式告知其他线程。当一个域被声明为volatile类型后,编译器与运行时会监视这个变量:它是共享的,而且对它的操作不会与其他内存操作一起被重排序,volatile变量不会缓存在寄存器或者缓存在其他处理器隐藏的地方,因此读一个volatile类型的变量时,总是返回由某一线程所写入的最新值。
    出于简易性或可伸缩性的考虑,您可能倾向于使用 volatile 变量而不是锁。当使用 volatile 变量而非锁时,某些习惯用法更加易于编码和阅读。此外,volatile 变量不会像锁那样造成线程阻塞,因此也很少造成可伸缩性问题。在某些情况下,如果读操作远远大于写操作,volatile 变量还可以提供优于锁的性能优势,但是请注意volatile只保证可见性,不保证原子性。
    只有满足如下条件才能使用volatile 变量:
    A. 对变量的写操作不依赖于当前值。
    B. 该变量没有包含在具有其他变量的不变式中。

    五、线程封闭
    访问共享的、可变的数据要求使用同步。线程封闭是一种将数据仅在单线程中访问而不共享,不需要任何同步的最简单的实现线程安全的方式。
    当对象(无论本身是否线程安全)封闭在一个线程中,会自动成为线程安全,线程封闭的常用做法有:
    (1).栈限制:
    栈限制是线程封闭的一种特例,只能通过本地变量才可以触及对象,本地变量使对象限制在执行线程中,存在于执行线程栈,其他线程无法访问这个栈,从而确保线程安全。栈限制的例子如下:

    /**
     *栈限制例子中animals不能逸出,否则就会破坏限制性
     **/
    public int loadTheArk(Collection<Animal> candidates){  
        SortedSet<Animal> animals;  
        int numPairs = 0;  
        Animal candidate = null;  
    
        //animals被限制在本地方法栈中  
        animals = new TreeSet<Animal>(new SpeciesGenderComparator());  
        animals.addAll(candidates);  
        for(Animal a : animals){  
            if(candidate == null || !candidate.isPotentialMate(a)){  
                candidate = a;  
            }else{  
                ark.load(new AnimalPair(candidate, a));  
                ++numPairs;  
                candidate = null;  
            }  
        }  
        return numPairs;  
    }  

    (2)ThreadLocal:
    ThreadLocal线程本地变量是一种规范化的维护线程限制的方式,它允许将每个线程与持有数值的对象关联在一起,为每个使用它的线程维护一份单独的拷贝。ThreadLocal提供了set和get访问器,get总是返回由当前线程通过set设置的最新值。
    ThreadLocal线程本地变量通过用于防止在基于可变的单例(singleton)或全局变量的设计中,出现不正确的共享。ThreadLocal线程本地变量的例子如下:

    private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>(){  
        public Connection initialValue(){  
            return DriverManager.getConnection(DB_URL);  
        }  
    };  
    public static Connection getConnection(){  
        return connectionHolder.get();  
    }  
    

    六、发布和逸出
    1.发布:发布一个对象是指使该对象能够被当前范围之外的代码所使用,例如将一个引用存储到其他代码可以访问的地方;在一个非私有的方法中返回该引用;将该对象传递到其他类的方法中等。安全发布的几种模式:在静态初始化函数中初始化一个对象引用;将对象的引用保存到validate类型的域或者AtomicReference对象中;将对象引用保存到某个正确构造对象的final类型域中;将对象的引用保存到一个有锁保护的域中。
    最常见的发布方式是将对象的引用存储到公共静态域中,例如:

    public static Set<Secrte> knownSecrets;  
    public void initialize(){  
        knowSecrets = new HashSet<Secret>();  
    }  

    2.逸出
    逸出是指一个对象在尚未准备好时就将它发布。
    对象逸出会导致对象的内部状态被暴露,可能危及到封装性,使程序难以维持稳定;若发布尚未构造完成的对象,可能危及线程安全问题。
    最常见的逸出是this引用在构造时逸出,导致this引用逸出的常见错误有:
    A.在构造函数中启动线程:
    当对象在构造函数中显式还是隐式创建线程时,this引用几乎总是被新线程共享,于是新的线程在所属对象完成构造之前就能看见它。
    避免构造函数中启动线程引起的this引用逸出的方法是不要在构造函数中启动新线程,取而代之的是在其他初始化或启动方法中启动对象拥有的线程。
    B.在构造方法中调用可覆盖的实例方法:
    在构造方法中调用那些既不是private也不是final的可被子类覆盖的实例方法时,同样导致this引用逸出。
    避免此类错误的方法时千万不要在父类构造方法中调用被子类覆盖的方法。
    C.在构造方法中创建内部类:
    在构造方法中创建内部类实例时,内部类的实例包含了对封装实例的隐含引用,可能导致隐式this逸出。例子如下:

    public class ThisEscape {  
        public ThisEscape(EventSource source) {  
            source.registerListener(new EventListener() {  
                public void onEvent(Event e) {  
                    doSomething(e);  
                }  
            });  
        }  
    }  

    上述例子中的this逸出可以使用工厂方法来避免,例子如下:

    public class SafeListener {  
        private final EventListener listener;  
    
        public SafeListener(){  
            listener = new EventListener(){  
                public void onEvent(Event e){  
                    doSomething(e);  
                }  
            );  
        }  
    
        public static SafeListener newInstance(EventSource source) {  
            SafeListener safe = new SafeListener();  
            source.registerListener(safe.listener);  
            return safe;  
        }  
    }  
    

    七、向已有线程安全类添加新功能
    如果JDK或者第三方类库提供的线程安全类只能满足我们大部分的要求,即不能完全满足要求时就需要对其进行添加新操作,这个看似简单的问题往往会引起线程安全问题。
    以向一个线程安全的List添加一个原子的缺少即加入操作为例,有如下方法:
    (1).修改原始类:
    添加一个新原子操作最安全的方式就是修改原始类,在原始类中添加新操作,但是软件设计的开放闭合原则以及有可能无法得到源码(或无法自由修改源码)等问题决定修改原始类是最不可能的。即便可以修改原始类,也要保证理解原有的同步策略,维持原有的设计。

    (2).扩展原始类:
    如果原始类在设计上是可扩展的(没有声名为final,即允许继承),则扩展原始类并添加新方法,例子如下:

    public class BetterVector<E> extends Vector<E> {  
        public synchronized boolean putIfAbsent(E x){  
            boolean absent = !contains(x);  
            if(absent){  
                add(x);  
            }  
            return absent;  
        }  
    }  

    扩展原始的线程安全类要特别小心,虽然做法非常直观,但是一定要明白原始的线程安全类的同步策略,新扩展的类要使用和原始类相同的锁来控制对基本类状态的并发访问,这种访问有很大的局限性,如果原始类使用的是内部私有锁同步策略或者没有告知使用者同步策略,则该方式是不能支持的。
    Vector是使用内部锁来控制并发访问的,因此上面代码中BetterVector也使用内部锁控制并发访问是可以维持Vector同步策略。

    (3).客户端加锁:
    对于一个由Collections.synchronizedList封装的ArrayList,客户端不知道同步封装工厂方法返回的List对象的同步策略的时候,前面所介绍的扩展原始类方案就无法支持,这时我们就需要将新增功能添加在客户端,并在客户端进行加锁同步。
    客户端加锁要非常小心,不注意就会发生错误,下面例子演示一个常见的错误:

    public class ListHelper<E> {  
        public List<E> list = Collections.synchronizedList(new ArrayList<E>());  
    
        public synchronized boolean putIfAbsent(E x) {  
            poolean absent = !list.contains(x);  
            if (absent) {  
                list.add(x);  
            }  
            return absent;  
        }  
    }  
    

    上述代码错误在于使用了与线程同步List不同的锁,上面代码的putIfAbsent方式使用的是ListHelper对象的内部锁,而线程同步List的其他原子操作肯定用的不是ListHelper对象内部锁,因此putIfAbsent对于List的其他操作而言并不是原子化的,上述代码是很多人经常不小心犯的错误。
    避免上述的错误的办法是让客户端的putIfAbsent方法所使用的锁与List的其他操作所使用的锁是同一个锁,正确的代码如下:

    public class ListHelper<E> {  
        public List<E> list = Collections.synchronizedList(new ArrayList<E>());  
    
        public boolean putIfAbsent(E x) {  
            synchronized (list) {  
                poolean absent = !list.contains(x);  
                if (absent) {  
                    list.add(x);  
                }  
                return absent;  
            }  
        }  
    }  

    (4).组合:
    面向对象有两种常用的扩展方式:继承(is-a)和组合(has-a),设计原则也经常推荐优先使用组合,除非情况非常合适,否则尽量少使用继承。
    组合对于向现有线程安全类添加新功能时同样适合,通过添加一层额外的锁层,组合对象将操作委托给底层List实例,无论底层List实例是否实现线程安全,组合对象的putIfAbsent方法都可以保证操作的原子性,例子如下:

    public class ImprovedList<T> implements List<T>{  
        private final List<T> list;  
        public ImprovedList<T>(List<T> list){  
            this.list = list;  
        }  
        public synchronized boolean putIfAbsent(T x){  
            boolean absent= !list.contains(x);  
            if(absent){  
                list.add(x);  
            }  
            return absent;  
        }  
        public synchronized void clear(){  
            list.clear();  
        }  
        ......  
    }  
    
    展开全文
  • 对象的共享和可变性 共享意味这变量可以由多个线程访问。可变意味着变量的值在生命周期内可以...所谓无状态对象指类或方法中不包含任何域包含其他累中域的引用,说简单一点就是,所有的参数,都线程请求...
  • 在这里所涉及的安全威胁不仅仅指有恶意的代理模式,而且也包含因有恶意主机引发的威胁。前者相当于有 恶意的移动代理攻击主机的情形,具体可以认为对计算资源的非法访问以及对计算资源的过剩消耗。后者相当...
  • Ajax安全技术.pdf

    2018-10-18 14:34:15
    《AJAX安全技术》适合广大基于AJAX开发Web程序的开发人员参考学习,同时可作为高等院校相关专业师生的参考用书。 第1章AJAX安全介绍1 1.1AJAX基础知识2 1.1.1什么AJAX2 1.1.2动态HTML(DHTML)10 1.2AJAX架构...
  • 如何在内河水路运输建立一套船舰识别系统,自动化识别船舰类型和状态是重要的议题之。有鉴于此,本研究提出一套船舰识别系统,包含智能桥墎设备和船舰识别服务器。其中,船舰识别服务器主要包含轮廓强化方法和迁移...
  • 如何在内河水路运输建立一套船舰识别系统,自动化识别船舰类型和状态是重要的议题之。有鉴于此,本研究提出一套船舰识别系统,包含智能桥墎设备和船舰识别服务器。其中,船舰识别服务器主要包含轮廓强化方法和迁移...
  • 安全性验证问题难以解决,即使线性混成自动机,它的可达性问题被证明不可判定的。现有工具大都使用多面体计算来计算线性混成自动机的可达状态空间集,复杂度高,可处理问题规模非常有限。为了避免这类问题,...
  • 如今家居、商铺等民用市场的安全监控已经显得越来越重要,犯罪分子的手段不断升级安全监控提出了更高的要求,传统的视频监控在防盗保全这领域已经越来越力不从心了。手机视频监控以普通老百姓为基础,所包含的...
  • 【51CTO.com独家特稿】前些日子的udev溢出***...编者按:SELinux是一种基于 域-类型 模型(domain-type)的强制访问控制(MAC)安全系统,它由NSA编写并设计成内核模块包含到内核中,相应的某些安全相关的应用被打...
  • 当某产品测试完成后,点击主界面“保存当前信息”按钮保存当前测试纪录,如果开机后第次保存测试纪录,系统将弹出“保存框”让你选择将数据保存到哪个记录库,在此你可以建个新的记录库,可以打开以往的测试...
  • 7.7 以交互方式冒充另一种设备 149 7.8 使用cURL模仿搜索引擎 151 7.9 通过假造Referer头信息来伪造工作流程 152 7.10 仅获取HTTP头 153 7.11 使用cURL发送POST请求 154 7.12 保持会话状态 156 7.13 操纵Cookie 157 ...
  • adb1.0.26包含fastboot.exe

    2019-03-05 15:11:03
    从 emulator-5554 这个名字可以看出它是一个 Android 模拟器,而 10.129.164.6:5555 这种形为 <IP>:<Port> 的 serialNumber 一般是无线连接的设备或 Genymotion 等第三方 Android 模拟器。 常见异常输出: 没有...
  • 、线程安全个对象是否需要线性安全的,取决于它是否需要被多个线程访问当多个线程访问某个类时,不管运行时环境采用何调度方式或者这些线程将如何交替执行,并且在主调代码中不需要额外的同步,这个类都...
  • 、线程安全个对象是否需要线性安全的,取决...1. 无状态对象无状态对象不包含域,包含与其他类中域的引用,计算过程中的临时状态仅存在于线程栈中的局部变量上,并且只能由正在执行的线程访问。访问无状
  • 二十三设计模式【PDF版】

    热门讨论 2011-05-30 14:13:49
    GoF 的设计模式表面上好象也是一种具体的"技术",而且新的设计模式不断在出现,设计模式自有其自己的发展轨道,而这 些好象和 J2EE .Net 等技术无关! 实际上,GoF 的设计模式并不是一种具体"技术",它讲述的是...
  • 如果个类既不包含任何域,包含任何对其他类中域的引用。则它一定状态的对象,无状态对象一定线程安全的 2.竞态条件 并发编程中,由于不恰当的执行时序导致不正确的结果。当某个计算结果的正确性取决于...
  • PHP文件包含漏洞是一种常见的漏洞,而通过PHP文件包含漏洞入侵网站,甚至拿到网站的WebShell的案例是不胜枚举。本期美创安全实验室将带大家了解PHP文件包含漏洞的产生原因和漏洞原理。漏洞简介文件包含漏洞(File ...
  • JAVA并发编程(

    2018-07-21 20:44:56
    状态对象(即这个类不包含任何域包含任何对其他类中域的引用)一定线程安全的。 竞态条件:当某个计算的正确性取决于多个线程的交替执行时序时,那么就会发生竞态条件。 内置锁:每个java...
  • 什么VLAN

    2013-10-23 09:59:12
     IP 组播实际上也是一种VLAN的定义,即认为一个组播组就是一个VLAN,这种划分的方法将VLAN扩大到了广域网,因此这种方法具有更大的灵活性,而且很容易通过路由器进行扩展,当然这种方法不适合局域网,主要是效率...
  • 8.提供方便、灵活、强悍的符号输入方法,一种符号可多种方式输入; 9.可快捷输入当前日期、时间、星期、农历,自动进行数字大小写转换; 10.支持快捷调用外部程序,如命令行、Office软件、截图工具(已经整合)、...
  • Google Chrome,中文名为“谷歌浏览器”,是一个由Google公司开发的网页浏览器。与苹果公司的safari相抗衡,浏览速度在众多浏览器中走在前列,属于高端浏览器。采用BSD许可证授权并开放源代码,开源计划名为Chromium...
  • oauth2生成jwt令牌

    2020-09-06 12:55:54
    JWT是一种用于双方之间传递安全信息的简洁的、URL安全的表述性声明规范。也是一种token,但是和token有一些不同。默认情况下,OAuth2生成的token为自定义的UUID的token,里面没有用户信息,但是jwt中包含了用户信息...
  •  当他运行在无 JavaScript 状态,这是一安全的选择。而且,当页面被载完,所有的图片会将被载完。然而,这个方式只适用于少量的图片。 在文档中包含第一张图片,并且有一个创建幻灯片功能的服务器端脚本。 ...
  • SELinux是Security-Enhanced Linux的简称,SELinux是一种基于 域-类型 模型(domain-type)的强制访问控制(MAC)安全系统,它由NSA编写并设计成内核模块包含到内核中,相应的某些安全相关的应用被打了SELinux的...
  • DirectX修复工具(DirectX Repair)是一款系统级工具软件,简便易用。本程序为绿色版,无需安装,可直接运行。 本程序的主要功能是检测当前系统的DirectX状态,如果发现异常则进行修复。程序主要针对0xc000007b问题...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 523
精华内容 209
关键字:

安全是一种安全状态也包含