GVKun编程网logo

Java中的锁(java中的锁有哪些)

16

如果您对Java中的锁感兴趣,那么本文将是一篇不错的选择,我们将为您详在本文中,您将会了解到关于Java中的锁的详细内容,我们还将为您解答java中的锁有哪些的相关问题,并且为您提供关于6-1java

如果您对Java中的锁感兴趣,那么本文将是一篇不错的选择,我们将为您详在本文中,您将会了解到关于Java中的锁的详细内容,我们还将为您解答java中的锁有哪些的相关问题,并且为您提供关于6-1 java中的面相对象;使用包管理java中的类;java中的访问修饰符;java中的this关键字、java中的锁 Lock、Java中的锁----重入锁、Java中的锁--同步锁和JUC包中的锁的有价值信息。

本文目录一览:

Java中的锁(java中的锁有哪些)

Java中的锁(java中的锁有哪些)

一个简单的锁

让我们从java中的一个同步块开始:

1 public class Counter{
2     private int count = 0;
3  
4     public int inc(){
5         synchronized(this){
6             return ++count;
7         }
8     }
9 }

可以看到在inc()方法中有一个synchronized(this)代码块。该代码块可以保证在同一时间只有一个线程可以执行return ++count。虽然在synchronized的同步块中的代码可以更加复杂,但是++count这种简单的操作已经足以表达出线程同步的意思。

以下的Counter类用Lock代替synchronized达到了同样的目的:

01 public class Counter{
02     private Lock lock = new Lock();
03     private int count = 0;
04  
05     public int inc(){
06         lock.lock();
07         int newCount = ++count;
08         lock.unlock();
09         return newCount;
10     }
11 }

lock()方法会对Lock实例对象进行加锁,因此所有对该对象调用lock()方法的线程都会被阻塞,直到该Lock对象的unlock()方法被调用。

这里有一个Lock类的简单实现:

01 public class Counter{
02 public class Lock{
03     private boolean isLocked = false;
04  
05     public synchronized void lock()
06         throws InterruptedException{
07         while(isLocked){
08             wait();
09         }
10         isLocked = true;
11     }
12  
13     public synchronized void unlock(){
14         isLocked = false;
15         notify();
16     }
17 }

注意其中的while(isLocked)循环,它又被叫做“自旋锁”。自旋锁以及wait()和notify()方法在线程通信这篇文章中有更加详细的介绍。当isLocked为true时,调用lock()的线程在wait()调用上阻塞等待。为防止该线程没有收到notify()调用也从wait()中返回(也称作虚假唤醒),这个线程会重新去检查isLocked条件以决定当前是否可以安全地继续执行还是需要重新保持等待,而不是认为线程被唤醒了就可以安全地继续执行了。如果isLocked为false,当前线程会退出while(isLocked)循环,并将isLocked设回true,让其它正在调用lock()方法的线程能够在Lock实例上加锁。

当线程完成了临界区(位于lock()和unlock()之间)中的代码,就会调用unlock()。执行unlock()会重新将isLocked设置为false,并且通知(唤醒)其中一个(若有的话)在lock()方法中调用了wait()函数而处于等待状态的线程。

锁的可重入性
Java中的synchronized同步块是可重入的。这意味着如果一个java线程进入了代码中的synchronized同步块,并因此获得了该同步块使用的同步对象对应的管程上的锁,那么这个线程可以进入由同一个管程对象所同步的另一个java代码块。下面是一个例子:

1 public class Reentrant{
2     public synchronized outer(){
3         inner();
4     }
5  
6     public synchronized inner(){
7         //do something
8     }
9 }

注意outer()和inner()都被声明为synchronized,这在Java中和synchronized(this)块等效。如果一个线程调用了outer(),在outer()里调用inner()就没有什么问题,因为这两个方法(代码块)都由同一个管程对象(”this”)所同步。如果一个线程已经拥有了一个管程对象上的锁,那么它就有权访问被这个管程对象同步的所有代码块。这就是可重入。线程可以进入任何一个它已经拥有的锁所同步着的代码块。

前面给出的锁实现不是可重入的。如果我们像下面这样重写Reentrant类,当线程调用outer()时,会在inner()方法的lock.lock()处阻塞住。

01 public class Reentrant2{
02     Lock lock = new Lock();
03  
04     public outer(){
05         lock.lock();
06         inner();
07         lock.unlock();
08     }
09  
10     public synchronized inner(){
11         lock.lock();
12         //do something
13         lock.unlock();
14     }
15 }

调用outer()的线程首先会锁住Lock实例,然后继续调用inner()。inner()方法中该线程将再一次尝试锁住Lock实例,结果该动作会失败(也就是说该线程会被阻塞),因为这个Lock实例已经在outer()方法中被锁住了。

两次lock()之间没有调用unlock(),第二次调用lock就会阻塞,看过lock()实现后,会发现原因很明显:

01 public class Lock{
02     boolean isLocked = false;
03  
04     public synchronized void lock()
05         throws InterruptedException{
06         while(isLocked){
07             wait();
08         }
09         isLocked = true;
10     }
11  
12     ...
13 }

一个线程是否被允许退出lock()方法是由while循环(自旋锁)中的条件决定的。当前的判断条件是只有当isLocked为false时lock操作才被允许,而没有考虑是哪个线程锁住了它。

为了让这个Lock类具有可重入性,我们需要对它做一点小的改动:

01 public class Lock{
02     boolean isLocked = false;
03     Thread  lockedBy = null;
04     int lockedCount = 0;
05  
06     public synchronized void lock()
07         throws InterruptedException{
08         Thread callingThread =
09             Thread.currentThread();
10         while(isLocked && lockedBy != callingThread){
11             wait();
12         }
13         isLocked = true;
14         lockedCount++;
15         lockedBy = callingThread;
16   }
17  
18     public synchronized void unlock(){
19         if(Thread.curentThread() ==
20             this.lockedBy){
21             lockedCount--;
22  
23             if(lockedCount == 0){
24                 isLocked = false;
25                 notify();
26             }
27         }
28     }
29  
30     ...
31 }

注意到现在的while循环(自旋锁)也考虑到了已锁住该Lock实例的线程。如果当前的锁对象没有被加锁(isLocked = false),或者当前调用线程已经对该Lock实例加了锁,那么while循环就不会被执行,调用lock()的线程就可以退出该方法(译者注:“被允许退出该方法”在当前语义下就是指不会调用wait()而导致阻塞)

除此之外,我们需要记录同一个线程重复对一个锁对象加锁的次数。否则,一次unblock()调用就会解除整个锁,即使当前锁已经被加锁过多次。在unlock()调用没有达到对应lock()调用的次数之前,我们不希望锁被解除。

现在这个Lock类就是可重入的了。

锁的公平性

Java的synchronized块并不保证尝试进入它们的线程的顺序。因此,如果多个线程不断竞争访问相同的synchronized同步块,就存在一种风险,其中一个或多个线程永远也得不到访问权 —— 也就是说访问权总是分配给了其它线程。这种情况被称作线程饥饿。为了避免这种问题,锁需要实现公平性。本文所展现的锁在内部是用synchronized同步块实现的,因此它们也不保证公平性。饥饿和公平中有更多关于该内容的讨论。

在finally语句中调用unlock()

如果用Lock来保护临界区,并且临界区有可能会抛出异常,那么在finally语句中调用unlock()就显得非常重要了。这样可以保证这个锁对象可以被解锁以便其它线程能继续对其加锁。以下是一个示例:

查看源代码
打印 帮助
1 lock.lock();
2 try{
3     //do critical section code,
4     //which may throw exception
5 } finally {
6     lock.unlock();
7 }

这个简单的结构可以保证当临界区抛出异常时Lock对象可以被解锁。如果不是在finally语句中调用的unlock(),当临界区抛出异常时,Lock对象将永远停留在被锁住的状态,这会导致其它所有在该Lock对象上调用lock()的线程一直阻塞。

6-1 java中的面相对象;使用包管理java中的类;java中的访问修饰符;java中的this关键字

6-1 java中的面相对象;使用包管理java中的类;java中的访问修饰符;java中的this关键字

1.

1.面向对象三大特性:封装,继承,多态

2.封装的实现步骤:

2.使用包管理java中的类

3.java中的访问修饰符

4.java中的this关键字

 

 

 

 

 

java中的锁 Lock

java中的锁 Lock

锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源。

Lock

synchronized块或方法可以隐式的获取锁,但是它将锁的获取和释放固化了,即先获取再释放。

Lock,在JavaSE5之后,在使用时需要显式的获取和释放锁,相比于synchronized,拥有锁获取与释放的可操作性、可中断的获取锁以及超时获取锁等同步特性。

 

Lock接口提供的synchronized关键字不具备的主要特性

特性  描述
尝试非阻塞的获取锁 当前线程尝试获取锁,如果这一时刻锁没有被其它线程获取到,则成功获取并持有锁
能被中断地获取锁  与synchronized不同,获取到的锁能够响应中断,当获取到锁的线程被中断时,中断异常将会抛出,同时锁会被释放
超时获取锁 在指定的截止时间之前获取锁,如果截止时间到了仍旧无法获取锁,则返回

Lock接口API

方法名称 描述
void lock() 获取锁。如果锁不可用,出于线程调度目的,将禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态
void lockInterruptibly() throws InterruptedException
  • 如果当前线程未被中断,则获取锁。
  • 如果锁可用,则获取锁,并立即返回。
  • 如果锁不可用,出于线程调度目的,将禁用当前线程,并且在发生以下两种情况之一以前,该线程一直处于休眠状态:
  1. 锁由当前线程获得
  2. 其他某个线程中断当前线程,并且支持对锁获取的中断
  • 如果当前线程存在以下情况,则将抛出InterruptedException,并清除当前线程的中断状态
  1. 在进入此方法时已经设置了该线程的中断状态
  2. 在获取锁时被中断,并且支持对锁获取的中断
boolean tryLock() 尝试非阻塞的获取锁。
仅在调用时锁为空闲状态才获取锁。如果锁可用,则获取锁,并立即返回值true,如果锁不可用,则此方法将立即返回值false
boolean tryLock(long time,TimeUnit unit) throws InterruptedException

超时的获取锁,当前线程在以下3种情况下会返回:

  1. 当前线程在超时时间内获得了锁
  2. 当前线程在超时时间内被中断
  3. 超时时间结束,返回false
void unlock() 释放锁
Condition newCondition() 获取等待通知组件,该组件和当前的锁绑定,当前线程只有获得了锁,才能调用该组件的wait()方法,而调用后,当前线程将释放

 

Java中的锁----重入锁

Java中的锁----重入锁

ReentrantLock

重入锁(ReentrantLock):支持重进入的锁,他表示该锁能够支持一个线程对资源的重复加锁。在调用lock()方法时,已经获取到锁的线程,能够再次调用lock()方法获取锁而不被阻塞。 公平锁:在绝对时间上,先对锁进行获取的请求一定先被满足,也就是等待时间最长的线程最优先获取锁。反之则是不公平锁。

1.实现重进入

  1. 线程再次获取锁。锁需要去识别获取锁的线程是否为当前占据锁的线程,如果是,则再次成功获取。

  2. 锁的最终释放。线程重复n次获取了锁,随后在第n次释放该锁后,其他线程能够获取到该锁。锁的最终释放要求锁对于获取进行计数自增,计数表示当前锁被重复获取的次数,而锁被释放时,计数自减,当计数等于0时表示所以经成功释放。

       /**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
            非公平性锁获取的示例

         */
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

该方法增加了再次获取同步状态的处理逻辑:通过判断当前线程是否为获取锁的线程来决定获取操作是否成功,如果是获取锁的线程再次请求,则将同步状态值进行增加并返回true,表示获取同步状态成功。 成功获取锁的线程再次获取锁,只是增加了同步状态值,这也就要求ReentrantLock在释放同步状态时减少同步状态值。

 protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

公平与非公平获取锁的区别

    /**
         * Fair version of tryAcquire.  Don''t grant access unless
         * recursive call or no waiters or is first.
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

tryAcquire 是公平锁的获取,同 nonfairTryAcquire 相比,多了判断条件:hasQueuedPredecessors();既加入了同步队列中当前节点是否有前驱节点的判断,如果该方法返回true,则表示有线程比当前线程更早地请求获取锁,因此需要等待前驱线程获取并释放之后才能继续获取锁。

读写锁

读写锁:在同一时刻可以允许多个多线程访问,但是在写线程访问时,所有的读线程和其他写线程均被阻塞。读写锁维护了一对锁,一个读锁和一个写锁,通过分离读锁和写锁,使得并发性相比一般的排他锁有了很大的提示。

Java并发包提供读写锁的实现是ReentrantReadWriteLock();特性:公平性选择,重进入,锁降级。

读写锁的接口与示例

ReadWriteLock 仅定义了 获取读锁和写锁的两个方法,既 readLock()方法 和 WriteLock() 方法,而其实现---ReentranReadWriteLock,除了实现接口方法,还提供了一些便于外界监控其内部状态的方法。

package com.lock;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Created by cxx on 2018/1/17.
 * 缓存示例说明读写锁的实现方式
 */
public class Cache {
    
    static Map<String ,Object> map = new HashMap<String,Object>();
    static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    static Lock r = rwl.readLock();
    static Lock w = rwl.writeLock();
    
    //获取一个key对应的value
    public static final Object get(String key){
        r.lock();
        try {
            return map.get(key);
            
        }finally {
            r.unlock();
        }
    }
    
    // 设置key对应的value,并返回旧的value
    public static final Object put(String key ,Object value){
        w.lock();
        try {
            return map.put(key,value);
        } finally {
            w.unlock();
        }
    }
    
    //情况所有的内容
    public static final void clear(){
        w.lock();
        
        try {
            map.clear();
        } finally {
            w.unlock();
        }
    }
    
}

Cache组合一个非线程安全的HashMap作为缓存的实现,同时使用读写锁的读锁和写锁来保证Cache是线程安全的。在操作get() 方法中,需要获取读锁,这使得并发访问该方法时不会被阻塞。写操作put 方法和clear方法,在更新HashMap是必须提前获取写锁,当获取写锁后,其他线程对于读锁和写锁的获取均被阻塞,而只有写锁被释放之后,其他读写操作才能继续。

读写锁的实现方式

ReentrantReadWriteLock 的实现,主要包括:读写状态的设计,写锁的获取与释放、读锁的获取与释放以及锁降级。

读写状态的设计

读写锁同样依赖自定义同步器实现同步功能,而读写状态就是其同步器的同步状态。同步状态表示锁被一个线程重复获取的次数,而读写锁的自定义同步器需要在同步状态上维护多个读线程和一个写线程的状态,使得该状态的设计成为读写锁实现的关键。

如果在一个整型变量上维护多种状态,需要”按位切割使用“这个变量。高16位表示读,低16位表示写。

结论:同步状态值S,S不等于0时,当写状态(S & 0x0000FFFF) 等于 0 时,则读状态(s >> 16) 大于 0,既读锁已被获取。

写锁的获取与释放

写锁是一个支持重进入的排他锁。如果当前线程已经获取了写锁,则增加写状态。如果当前线程在获取写锁时,读锁已经被获取(读状态不为0)或者该线程不是已经获取写锁的线程,则当前线程进入等待状态。

        protected final boolean tryAcquire(int acquires) {
            /*
             * Walkthrough:
             * 1. If read count nonzero or write count nonzero
             *    and owner is a different thread, fail.
             * 2. If count would saturate, fail. (This can only
             *    happen if count is already nonzero.)
             * 3. Otherwise, this thread is eligible for lock if
             *    it is either a reentrant acquire or
             *    queue policy allows it. If so, update state
             *    and set owner.
             */
            Thread current = Thread.currentThread();
            int c = getState();
            int w = exclusiveCount(c);
            if (c != 0) {
                // (Note: if c != 0 and w == 0 then shared count != 0)
                if (w == 0 || current != getExclusiveOwnerThread())
                    return false;
                if (w + exclusiveCount(acquires) > MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                // Reentrant acquire
                setState(c + acquires);
                return true;
            }
            if (writerShouldBlock() ||
                !compareAndSetState(c, c + acquires))
                return false;
            setExclusiveOwnerThread(current);
            return true;
        }

除了重入条件的判断之外,增加了一个读锁是否存在的判断。如果存在读锁,则写锁不能被获取。只有等待其他读线程都释放了读锁,写锁才能被当前线程获取,而写锁一旦被获取,则其他读写线程的后续访问均被阻塞。

读锁的获取与释放

读锁是一个支持重进入的共享锁,他能够被多个线程同时获取,在没有其他写线程访问(或者写状态为0)时,读锁总会被成功地获取,而所做的也只是(线程安全的)增加读状态。读状态时所有线程获取读锁次数的总和,而每个线程各自获取读锁的次数只能选择保存在ThreadLocal中,由线程自身维护,这使获取读锁的实现变得复杂。

      protected final int tryAcquireShared(int unused) {
            /*
             * Walkthrough:
             * 1. If write lock held by another thread, fail.
             * 2. Otherwise, this thread is eligible for
             *    lock wrt state, so ask if it should block
             *    because of queue policy. If not, try
             *    to grant by CASing state and updating count.
             *    Note that step does not check for reentrant
             *    acquires, which is postponed to full version
             *    to avoid having to check hold count in
             *    the more typical non-reentrant case.
             * 3. If step 2 fails either because thread
             *    apparently not eligible or CAS fails or count
             *    saturated, chain to version with full retry loop.
             */
            Thread current = Thread.currentThread();
            int c = getState();
            if (exclusiveCount(c) != 0 &&
                getExclusiveOwnerThread() != current)
                return -1;
            int r = sharedCount(c);
            if (!readerShouldBlock() &&
                r < MAX_COUNT &&
                compareAndSetState(c, c + SHARED_UNIT)) {
                if (r == 0) {
                    firstReader = current;
                    firstReaderHoldCount = 1;
                } else if (firstReader == current) {
                    firstReaderHoldCount++;
                } else {
                    HoldCounter rh = cachedHoldCounter;
                    if (rh == null || rh.tid != getThreadId(current))
                        cachedHoldCounter = rh = readHolds.get();
                    else if (rh.count == 0)
                        readHolds.set(rh);
                    rh.count++;
                }
                return 1;
            }
            return fullTryAcquireShared(current);
        }

锁降级

锁降级指的是写锁降级成为读锁。如果当前线程用于写锁,然后将其释放,最后在获取读锁,这种分段完成的过程不能称之为锁降级。锁降级是指把持住写锁,在获取到读锁,随后释放写锁的过程。

public void processData(){
        readLock.lock();
        if (!update) {
            //必须先释放读锁
            readLock.unlock();
            //锁降级从写锁获取到开始
            writeLock.lock();
            try {
                if (!update){
                    //准备数据的流程(略)
                    update = true;
                }
                readLock.lock;
            }finally {
                writeLock.unlock();
            }
            //锁降级完成,写锁降级为读锁
        }
        
        try {
            //使用数据的流程
        }finally {
            readLock.unLock();
        }
    }

锁降级的必要性:主要是为了保证数据的可见性,如果当前线程不获取读锁而是直接释放写锁,假设此刻另一个线程获取了写锁并修改了数据,那么当前线程无法感知线程T的数据更新。如果当前线程获取读锁,既遵循锁降级的步骤,则线程T将会被阻塞,直到当前线程使用数据并释放读锁之后,线程T才能获取写锁进行数据更新。

RentrantReadWriteLock不支持所升级,目的也是保证数据可见性,如果读锁已被多个线程获取,其中任意线程成功获取了写锁并更新了数据,则其更新对其他获取到读锁的线程是不可见的。

Java中的锁--同步锁和JUC包中的锁

Java中的锁--同步锁和JUC包中的锁

这篇文章主要为大家详细介绍了java concurrency之锁的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

根据锁的添加到Java中的时间,Java中的锁,可以分为"同步锁"和"JUC包中的锁"。

同步锁

  即通过synchronized关键字来进行同步,实现对竞争资源的互斥访问的锁。Java 1.0版本中就已经支持同步锁了。

  同步锁的原理是,对于每一个对象,有且仅有一个同步锁;不同的线程能共同访问该同步锁。但是,在同一个时间点,该同步锁能且只能被一个线程获取到。这样,获取到同步锁的线程就能进行CPU调度,从而在CPU上执行;而没有获取到同步锁的线程,必须进行等待,直到获取到同步锁之后才能继续运行。这就是,多线程通过同步锁进行同步的原理!  

立即学习“Java免费学习笔记(深入)”;

JUC包中的锁 

  相比同步锁,JUC包中的锁的功能更加强大,它为锁提供了一个框架,该框架允许更灵活地使用锁,只是它的用法更难罢了。

  JUC包中的锁,包括:Lock接口,ReadWriteLock接口,LockSupport阻塞原语,Condition条件,AbstractOwnableSynchronizer/AbstractQueuedSynchronizer/AbstractQueuedLongSynchronizer三个抽象类,ReentrantLock独占锁,ReentrantReadWriteLock读写锁。由于CountDownLatch,CyclicBarrier和Semaphore也是通过AQS来实现的;因此,我也将它们归纳到锁的框架中进行介绍。

  先看看锁的框架图,如下所示。

01. Lock接口

  JUC包中的 Lock 接口支持那些语义不同(重入、公平等)的锁规则。所谓语义不同,是指锁可是有"公平机制的锁"、"非公平机制的锁"、"可重入的锁"等等。"公平机制"是指"不同线程获取锁的机制是公平的",而"非公平机制"则是指"不同线程获取锁的机制是非公平的","可重入的锁"是指同一个锁能够被一个线程多次获取。 

02. ReadWriteLock

  ReadWriteLock 接口以和Lock类似的方式定义了一些读取者可以共享而写入者独占的锁。JUC包只有一个类实现了该接口,即 ReentrantReadWriteLock,因为它适用于大部分的标准用法上下文。但程序员可以创建自己的、适用于非标准要求的实现。 

03. AbstractOwnableSynchronizer/AbstractQueuedSynchronizer/AbstractQueuedLongSynchronizer

  AbstractQueuedSynchronizer就是被称之为AQS的类,它是一个非常有用的超类,可用来定义锁以及依赖于排队阻塞线程的其他同步器;ReentrantLock,ReentrantReadWriteLock,CountDownLatch,CyclicBarrier和Semaphore等这些类都是基于AQS类实现的。AbstractQueuedLongSynchronizer 类提供相同的功能但扩展了对同步状态的 64 位的支持。两者都扩展了类 AbstractOwnableSynchronizer(一个帮助记录当前保持独占同步的线程的简单类)。

04. LockSupport

  LockSupport提供“创建锁”和“其他同步类的基本线程阻塞原语”。 

  LockSupport的功能和"Thread中的Thread.suspend()和Thread.resume()有点类似",LockSupport中的park() 和 unpark() 的作用分别是阻塞线程和解除阻塞线程。但是park()和unpark()不会遇到“Thread.suspend 和 Thread.resume所可能引发的死锁”问题。 

05. Condition

  Condition需要和Lock联合使用,它的作用是代替Object监视器方法,可以通过await(),signal()来休眠/唤醒线程。
Condition 接口描述了可能会与锁有关联的条件变量。这些变量在用法上与使用 Object.wait 访问的隐式监视器类似,但提供了更强大的功能。需要特别指出的是,单个 Lock 可能与多个 Condition 对象关联。为了避免兼容性问题,Condition 方法的名称与对应的 Object 版本中的不同。 

06. ReentrantLock

  ReentrantLock是独占锁。所谓独占锁,是指只能被独自占领,即同一个时间点只能被一个线程锁获取到的锁。ReentrantLock锁包括"公平的ReentrantLock"和"非公平的ReentrantLock"。"公平的ReentrantLock"是指"不同线程获取锁的机制是公平的",而"非公平的  ReentrantLock"则是指"不同线程获取锁的机制是非公平的",ReentrantLock是"可重入的锁"。

  ReentrantLock的UML类图如下:

  (01) ReentrantLock实现了Lock接口。
  (02) ReentrantLock中有一个成员变量sync,sync是Sync类型;Sync是一个抽象类,而且它继承于AQS。
  (03) ReentrantLock中有"公平锁类"FairSync和"非公平锁类"NonfairSync,它们都是Sync的子类。ReentrantReadWriteLock中sync对象,是FairSync与NonfairSync中的一种,这也意味着ReentrantLock是"公平锁"或"非公平锁"中的一种,ReentrantLock默认是非公平锁。 

07. ReentrantReadWriteLock

  ReentrantReadWriteLock是读写锁接口ReadWriteLock的实现类,它包括子类ReadLock和WriteLock。ReentrantLock是共享锁,而WriteLock是独占锁。

  ReentrantReadWriteLock的UML类图如下:


       (01) ReentrantReadWriteLock实现了ReadWriteLock接口。
  (02) ReentrantReadWriteLock中包含sync对象,读锁readerLock和写锁writerLock。读锁ReadLock和写锁WriteLock都实现了Lock接口。
  (03) 和"ReentrantLock"一样,sync是Sync类型;而且,Sync也是一个继承于AQS的抽象类。Sync也包括"公平锁"FairSync和"非公平锁"NonfairSync。

08. CountDownLatch

  CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。 
  CountDownLatch的UML类图如下:

  CountDownLatch包含了sync对象,sync是Sync类型。CountDownLatch的Sync是实例类,它继承于AQS。 

09. CyclicBarrier

  CyclicBarrier是一个同步辅助类,允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。

  CyclicBarrier的UML类图如下:


  CyclicBarrier是包含了"ReentrantLock对象lock"和"Condition对象trip",它是通过独占锁实现的。
  CyclicBarrier和CountDownLatch的区别是:
  (01) CountDownLatch的作用是允许1或N个线程等待其他线程完成执行;而CyclicBarrier则是允许N个线程相互等待。
  (02) CountDownLatch的计数器无法被重置;CyclicBarrier的计数器可以被重置后使用,因此它被称为是循环的barrier。 

10. Semaphore

  Semaphore是一个计数信号量,它的本质是一个"共享锁"。

  信号量维护了一个信号量许可集。线程可以通过调用acquire()来获取信号量的许可;当信号量中有可用的许可时,线程能获取该许可;否则线程必须等待,直到有可用的许可为止。 线程可以通过release()来释放它所持有的信号量许可。

  Semaphore的UML类图如下:


和"ReentrantLock"一样,Semaphore包含了sync对象,sync是Sync类型;而且,Sync也是一个继承于AQS的抽象类。Sync也包括"公平信号量"FairSync和"非公平信号量"NonfairSync。

以上就是Java中的锁--同步锁和JUC包中的锁的详细内容,更多请关注php中文网其它相关文章!

今天的关于Java中的锁java中的锁有哪些的分享已经结束,谢谢您的关注,如果想了解更多关于6-1 java中的面相对象;使用包管理java中的类;java中的访问修饰符;java中的this关键字、java中的锁 Lock、Java中的锁----重入锁、Java中的锁--同步锁和JUC包中的锁的相关知识,请在本站进行查询。

本文标签: