• Lock and Reentrant


    Java provides a built-in locking mechanism for enforcing atomicity: the synchronized block. 

    There is no inherent relationship between an object's intrinsic lock and its state; an object's fields need not be guarded by its intrinsic lock, though this is a perfectly valid locking convention that is used by many classes. Acquiring the lock associated with an object does not prevent other threads from accessing that objectthe only thing that acquiring a lock prevents any other thread from doing is acquiring that same lock. The fact that every object has a built-in lock is just a convenience so that you needn't explicitly create lock objects

    locks enable serialized access to the code paths they guard. Serializing access to an object has nothing to do with object serialization (turning an object into a byte stream); serializing access means that threads take turns accessing the object exclusively, rather than doing so concurrently.

    synchronized block has two parts: a reference to an object that will serve as the lock, and a block of code to be guarded by that lock. A synchronized method is a shorthand for a synchronized block that spans an entire method body, and whose lock is the object on which the method is being invoked. (Static synchronized methods use the Class object for the lock.)

    synchronized (lock) {
        // Access or modify shared state guarded by lock
    }

    Reentrancy

    When a thread requests a lock that is already held by another thread, the requesting thread blocks. But because intrinsic locks are reentrant, if a thread tries to acquire a lock that it already holds, the request succeeds. Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis. [7] Reentrancy is implemented by associating with each lock an acquisition count and an owning thread. When the count is zero, the lock is considered unheld. When a thread acquires a previously unheld lock, the JVM records the owner and sets the acquisition count to one. If that same thread acquires the lock again, the count is incremented, and when the owning thread exits the synchronized block, the count is decremented. When the count reaches zero, the lock is released.

    Reentrancy facilitates encapsulation of locking behavior, and thus simplifies the development of object-oriented concurrent code. Without reentrant locks, the very natural-looking code in Listing 2.7, in which a subclass overrides a synchronized method and then calls the superclass method, would deadlock. Because the doSomething methods in Widget and LoggingWidget are both synchronized, each tries to acquire the lock on the Widget before proceeding. But if intrinsic locks were not reentrant, the call to super.doSomething would never be able to acquire the lock because it would be considered already held, and the thread would permanently stall waiting for a lock it can never acquire. Reentrancy saves us from deadlock in situations like this.

    Code that would Deadlock if Intrinsic Locks were Not Reentrant.
    public class Widget {
        public synchronized void doSomething() {
            ...
        }
    }
    
    public class LoggingWidget extends Widget {
        public synchronized void doSomething() {
            System.out.println(toString() + ": calling doSomething");
            super.doSomething();
        }
    }

    GuardBy Annotation

    The field or method to which this annotation is applied can only be accessed when holding a particular lock, which may be a built-in (synchronization) lock, or may be an explicit java.util.concurrent.Lock. The argument determines which lock guards the annotated field or method:

    • this : The intrinsic lock of the object in whose class the field is defined.
    • class-name.this : For inner classes, it may be necessary to disambiguate 'this'; the class-name.this designation allows you to specify which 'this' reference is intended
    • itself : For reference fields only; the object to which the field refers.
    • field-name : The lock object is referenced by the (instance or static) field specified by field-name.
    • class-name.field-name : The lock object is reference by the static field specified by class-name.field-name.
    • method-name() : The lock object is returned by calling the named nil-ary method.
    • class-name.class : The Class object for the specified class should be used as the lock object.
    @ThreadSafe
    public class SynchronizedFactorizer 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);
            }
        }
    }
    //suppose the above servlet is implement as the single instance mode by default.

    note:sychronize the shortest code path as we can . so .there is a improved sample code here .

    @ThreadSafe
    public class CachedFactorizer implements Servlet {
        @GuardedBy("this") private BigInteger lastNumber;
        @GuardedBy("this") private BigInteger[] lastFactors;
        @GuardedBy("this") private long hits;
        @GuardedBy("this") private long cacheHits;
    
        public synchronized long getHits() { return hits; }
        public synchronized double getCacheHitRatio() {
            return (double) cacheHits / (double) hits;
        }
    
        public void service(ServletRequest req, ServletResponse resp) {
            BigInteger i = extractFromRequest(req);
            BigInteger[] factors = null;
            synchronized (this) {
                ++hits;
                if (i.equals(lastNumber)) {
                    ++cacheHits;
                    factors = lastFactors.clone();
                }
            }
            if (factors == null) {
                factors = factor(i);
                synchronized (this)  {
                    lastNumber = i;
                    lastFactors = factors.clone();
                }
            }
            encodeIntoResponse(resp, factors);
        }
    }

    The restructuring of

    SynchronizedFactorizer 

    provides a balance between simplicity (synchronizing the entire method) and concurrency (synchronizing the shortest possible code paths).  

  • 相关阅读:
    mySQL练习题
    JAVA实现C/S结构小程序
    JavaLinkedHashSet练习
    关于Extjs删除分页后删除最后一条数据页面无效的问题。
    hibernate 插入,更新数据库错误
    错误!错误!错误!
    坑爹的oracle
    关于hibernate实体类
    第一个项目的需求分析
    Ueditor 单独使用上传图片及上传附件方法
  • 原文地址:https://www.cnblogs.com/malaikuangren/p/2593702.html
Copyright © 2020-2023  润新知