zoukankan      html  css  js  c++  java
  • 1.线程安全性

    一.原子性

    无状态对象一定是线程安全的,假设我们希望增加一个“命中计数器”来统计所处理的请求数量,一种直观的方法是增加一个long类型的域。

    @NotThreadSafe
    public class UnsafeCountingFactorizer extends GenericServlet implements Servlet {
        private long count = 0;
    
        public long getCount() {
            return count;
        }
    
        public void service(ServletRequest req, ServletResponse resp) {
            BigInteger i = extractFromRequest(req);
            BigInteger[] factors = factor(i);
            ++count;
            encodeIntoResponse(resp, factors);
        }
    
        void encodeIntoResponse(ServletResponse res, BigInteger[] factors) {
        }
    
        BigInteger extractFromRequest(ServletRequest req) {
            return new BigInteger("7");
        }
    
        BigInteger[] factor(BigInteger i) {
            // Doesn't really factor
            return new BigInteger[] { i };
        }
    }
    UnsafeCountingFactorizer 并非线程安全的,因为递增操作++count并非原子的。它包含三个独立的操作:读取count的值,将值加1,然后将计算结果写入count。

    1.竞态条件
    UnsafeCountingFactorizer 中存在多个竞态条件。当某个计算的正确性取决于多个线程的交替执行时序时,那么就会发生竞态条件。最常见的竞态条件类型就是“先检查后执行”操作。
    2.复合操作
    @ThreadSafe
    public class CountingFactorizer extends GenericServlet implements Servlet {
        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);
        }
    
        void encodeIntoResponse(ServletResponse res, BigInteger[] factors) {}
        BigInteger extractFromRequest(ServletRequest req) {return null; }
        BigInteger[] factor(BigInteger i) { return null; }
    }

    通过用AtoimcLong来代替long类型的计数器,能够确保所有对计数器状态的访问操作都是原子的。

    二.加锁机制

    假设我们希望提升Servlet的性能:将最近的计算结果缓存起来,当两个连续的请求对相同的数值进行因数分解时,可以直接使用上一次的计算结果,而无需重新计算。

    @NotThreadSafe
    public class UnsafeCachingFactorizer extends GenericServlet implements Servlet {
        private final AtomicReference<BigInteger> lastNumber
                = new AtomicReference<BigInteger>();
        private final AtomicReference<BigInteger[]> lastFactors
                = new AtomicReference<BigInteger[]>();
    
        public void service(ServletRequest req, ServletResponse resp) {
            BigInteger i = extractFromRequest(req);
            if (i.equals(lastNumber.get()))
                encodeIntoResponse(resp, lastFactors.get());
            else {
                BigInteger[] factors = factor(i);
                lastNumber.set(i);
                lastFactors.set(factors);
                encodeIntoResponse(resp, factors);
            }
        }
    
        void encodeIntoResponse(ServletResponse resp, BigInteger[] factors) {
        }
    
        BigInteger extractFromRequest(ServletRequest req) {
            return new BigInteger("7");
        }
    
        BigInteger[] factor(BigInteger i) {
            // Doesn't really factor
            return new BigInteger[]{i};
        }
    }

    这种方法并不正确。尽管这些原子引用本身都是线程安全的,但在UnsafeCachingFactorizer 中存在着竞态条件,这可能产生错误的结果。尽管对set方法每次调用都是原子的,但仍然无法同时更新lastNumber和lastFactores。在线程A获取这两个值的过程中,线程B可能修改了它们。

    1.内置锁

    Java提供了一种内置的锁机制来支持原子性:同步代码块。

    @ThreadSafe
    public class SynchronizedFactorizer extends GenericServlet implements Servlet {
        @GuardedBy("this") private BigInteger lastNumber;
        @GuardedBy("this") private BigInteger[] lastFactors;
    
        public synchronized void service(ServletRequest req,
                                         ServletResponse resp) {
            BigInteger i = extractFromRequest(req);
            if (i.equals(lastNumber))
                encodeIntoResponse(resp, lastFactors);
            else {
                BigInteger[] factors = factor(i);
                lastNumber = i;
                lastFactors = factors;
                encodeIntoResponse(resp, factors);
            }
        }
    
        void encodeIntoResponse(ServletResponse resp, BigInteger[] factors) {
        }
    
        BigInteger extractFromRequest(ServletRequest req) {
            return new BigInteger("7");
        }
    
        BigInteger[] factor(BigInteger i) {
            // Doesn't really factor
            return new BigInteger[] { i };
        }
    }

    2.重入

    三.用锁来保护状态

  • 相关阅读:
    git使用流程
    php5.3.*编译出现make: *** [ext/gd/libgd/gd_compat.lo] Error 1 解决方法 [转]
    linux用户和组的操作,vi编辑器的使用
    linux目录介绍
    linux和windows分区原理
    linux配置网络,配置lmap
    linux常用操作命令
    mysql数据库编程,内置函数,存储过程(循环插入)
    msql数据库触发器和连接mysql常用函数
    mysql数据库增加删除跟新,关联数据
  • 原文地址:https://www.cnblogs.com/wuwuyong/p/14226985.html
Copyright © 2011-2022 走看看