• 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.重入

    三.用锁来保护状态

  • 相关阅读:
    Large-Scale Oil Palm Tree Detection from High-Resolution Satellite Images Using Two-Stage Convolutional Neural Networks(worldview油棕树检测)
    Visual Detail Augmented Mapping for Small Aerial Target Detection(航片动态小目标检测)
    Large Kernel Matters —— Improve Semantic Segmentation by Global Convolutional Network(GCN全局卷积网络)
    Learning a Discriminative Feature Network for Semantic Segmentation(语义分割DFN,区别特征网络)
    Semantic Segmentation on Remotely Sensed Images Using an Enhanced Global Convolutional Network with Channel Attention and Domain Specific Transfer Learning
    Super-Resolution Restoration of MISR Images Using the UCL MAGiGAN System 超分辨率恢复
    python 中内存释放与函数传递numpy数组问题
    hdfs的shell命令
    副本策略
    数据分割
  • 原文地址:https://www.cnblogs.com/wuwuyong/p/14226985.html
Copyright © 2020-2023  润新知