Java中锁的分类及其一些有限的认知

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq1782/article/details/82151422

锁分类:

    1.公平锁和非公平锁

           公平锁是指多个线程按照申请锁的顺序来获取锁。比如ReentrantLock的内部同时实现了公平锁和非公平锁。提到ReentrantLock就不得不提到AQS,它同时也是CountDownLatch、Semaphore、FutureTask的基础。

                            非公平锁就是指后来的线程也有机会获得锁。其实Synchronized也属于非公平锁。

Provides a framework for implementing blocking locks and related synchronizers (semaphores, events, etc) that rely on first-in-first-out (FIFO) wait queues. (提供一个框架,用于实现依赖于先见先出队列的阻塞锁与同步器(信号量 事件 等等));This class is designed to be a useful basis for most kinds of synchronizers that rely on a single atomic value to represent state. (对应:private volatile int state) and which define what that state means in terms of this object being acquired or released(共享与独占状态)。Given these, the other methods in this class carry out all queuing and blocking mechanics.(给定(有人说翻译成考虑到)这些,这个类的其余方法进行/执行所有的排列和阻塞机制)。but only the atomically updated {@code int} value manipulated using methods {@link #getState}, {@link #setState} and {@link #compareAndSetState} is tracked(跟踪 ) with respect to(关于) synchronization.(但为了获得同步而只追踪使用三个方式来操作以原子方式更新的int值 state)。

protected final void setState(int newState) {

--final基本类型的话基本类型不可变 state不可变 引用 不能指向新引用 但引用里面的内容可变 final String编译器会优化 因为会被视为常量 常量是直接存储字面值而不是引用的。

String s0 = "ab"; 
final String s1 = getS1(); 
String s2 = "a" + s1; 
System.out.println((s0 == s2)); //result = false 
private static String getS1() {  return "b";   }

    分析:JVM对于字符串引用s1,它的值在编译期无法确定,只有在程序运行期调用方法后,将方法的返回值和"a"来动态连接并分配地址为s2,故上面 程序的结果为false。

      string+="hello"的操作事实上会自动被JVM优化成:

  StringBuilder str = new StringBuilder(string);

  str.append("hello");

  str.toString();

因为String的不可变性,所以引入了StringBuffer,又因为线程安全性引入了StringBuilder.

-----下面是引用别人的博客的 因为想偷懒一下下

JDK1.7后,intern方法还是会先去查询常量池中是否有已经存在,如果存在,则返回常量池中的引用,这一点与之前没有区别,区别在于,如果在常量池找不到对应的字符串,则不会再将字符串拷贝到常量池,而只是在常量池中生成一个对原字符串的引用。简单的说,就是往常量池放的东西变了:原来在常量池中找不到时,复制一个副本放到常量池,1.7后则是将在堆上的地址引用复制到常量池。
这里写图片描述

举例说明:

1 String str2 = new String("str")+new String("01");

2 str2.intern();

3 String str1 = "str01";

4 System.out.println(str2==str1);

在JDK 1.7下,当执行str2.intern();时,因为常量池中没有“str01”这个字符串,所以会在常量池中生成一个对堆中的“str01”的引用(注意这里是引用 ,就是这个区别于JDK 1.6的地方。在JDK1.6下是生成原字符串的拷贝),而在进行String str1 = “str01”;字面量赋值的时候,常量池中已经存在一个引用,所以直接返回了该引用,因此str1和str2都指向堆中的同一个字符串,返回true。

将中间23两行调换位置以后,因为在进行字面量赋值(String str1 = “str01″)的时候,常量池中不存在,所以str1指向的常量池中的位置,而str2指向的是堆中的对象,再进行intern方法时,对str1和str2已经没有影响了,所以返回false。

------可怜的setState

        state = newState;
    }

This class supports either or both a default <em>exclusive</em> mode and a <em>shared</em> mode.(支持排他模式(默认)或者共享模式)。 When acquired in exclusive mode, attempted acquires by other threads cannot succeed. Shared mode acquires by multiple(多个) threads may (but need not) succeed. This class does not understand these differences except in the mechanical sense(机械的意识) that when a shared mode acquire succeeds, the next waiting thread (if one exists) must also determine(确定) whether it can acquire as well. Threads waiting in the different modes share the same FIFO queue. Usually, implementation subclasses support only one of these modes, but both can come into play(积极的,起作用的) for example in a {@link ReadWriteLock}.Subclasses that support only exclusive or only shared modes need not define the methods supporting the unused mode.

isHeldExclusively() 方法将报告同步对于当前线程是否是独占的;使用当前 getState() 值调用 release(int) 方法则可以完全释放此对象;如果给定保存的状态值,那么 acquire(int) 方法可以将此对象最终恢复为它以前获取的状态。

You may also find the inherited(继承) methods from {@link AbstractOwnableSynchronizer} useful to keep track of(记录/跟踪) the thread owning an exclusive synchronizer.  You are encouraged to use them-- this enables monitoring(监视) and diagnostic(诊断) tools to assist(帮助) users in determining(确定) which threads hold locks.

Even though this class is based on an internal FIFO queue, it does not automatically enforce(强制) FIFO acquisition policies.  The core of exclusive synchronization takes the form(采取如下形式---):

Acquire:
     while (!tryAcquire(arg)) {
//获取不到自动入列
       <em>enqueue thread if it is not already queued</em>;
      <em>possibly block current thread</em>;
    }

 Release:
     if (tryRelease(arg))
//释放 解锁
       <em>unblock the first queued thread</em>;
(Shared mode is similar but may involve cascading signals.) 共享模式相似 但可能涉及到级联信号量

Because checks in acquire are invoked before enqueuing(因为在入列前需要调用检查线程状态), a newly acquiring thread may <em>barge(闯入) ahead of others that are blocked and queued.  However, you can, if desired(希望 渴求),define {@code tryAcquire} and/or {@code tryAcquireShared} to disable barging by internally invoking one or more of the inspection methods, thereby(以此方式) providing a <em>fair</em> FIFO acquisition order.
In particular(特别是), most fair synchronizers can define {@code tryAcquire} to return {@code false} if {@link #hasQueuedPredecessors} (a method specifically designed to be used by fair synchronizers) returns {@code true}.  Other variations(变化) are possible.

 非再进入的互斥锁类,它使用值 0 表示未锁定状态,使用 1 表示锁定状态。当非重入锁定不严格地需要当前拥有者线程的记录时,此类使得使用监视器更加方便。它还支持一些条件并公开了一个检测方法:

 class Mutex implements Lock, java.io.Serializable {

    // Our internal helper class
    private static class Sync extends AbstractQueuedSynchronizer {
      // Report whether in locked state
      protected boolean isHeldExclusively() { 
        return getState() == 1; 
      }

      // Acquire the lock if state is zero
      public boolean tryAcquire(int acquires) {
        assert acquires == 1; // Otherwise unused
       if (compareAndSetState(0, 1)) {
         setExclusiveOwnerThread(Thread.currentThread());
         return true;
       }
       return false;
      }

      // Release the lock by setting state to zero
      protected boolean tryRelease(int releases) {
        assert releases == 1; // Otherwise unused
        if (getState() == 0) throw new IllegalMonitorStateException();
        setExclusiveOwnerThread(null);
        setState(0);
        return true;
      }
       
      // Provide a Condition
      Condition newCondition() { return new ConditionObject(); }

      // Deserialize properly
      private void readObject(ObjectInputStream s) 
        throws IOException, ClassNotFoundException {
        s.defaultReadObject();
        setState(0); // reset to unlocked state
      }
    }

    // The sync object does all the hard work. We just forward to it.
    private final Sync sync = new Sync();

    public void lock()                { sync.acquire(1); }
    public boolean tryLock()          { return sync.tryAcquire(1); }
    public void unlock()              { sync.release(1); }
    public Condition newCondition()   { return sync.newCondition(); }
    public boolean isLocked()         { return sync.isHeldExclusively(); }
    public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
    public void lockInterruptibly() throws InterruptedException { 
      sync.acquireInterruptibly(1);
    }
    public boolean tryLock(long timeout, TimeUnit unit) 
        throws InterruptedException {
      return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
 }
 

以下是一个锁存器类,它类似于 CountDownLatch,除了只需要触发单个 signal 之外。因为锁存器是非独占的,所以它使用 shared 的获取和释放方法。

 class BooleanLatch {

    private static class Sync extends AbstractQueuedSynchronizer {
      boolean isSignalled() { return getState() != 0; }

      protected int tryAcquireShared(int ignore) {
        return isSignalled()? 1 : -1;
      }
        
      protected boolean tryReleaseShared(int ignore) {
        setState(1);
        return true;
      }
    }

    private final Sync sync = new Sync();
    public boolean isSignalled() { return sync.isSignalled(); }
    public void signal()         { sync.releaseShared(1); }
    public void await() throws InterruptedException {
      sync.acquireSharedInterruptibly(1);
    }
 }

 

猜你喜欢

转载自blog.csdn.net/qq1782/article/details/82151422