Java 7之多线程第11篇 - 读写锁

ReadWriteLock是ReentrantReadWriteLock的接口,而ReentrantReadWriteLock实现类中包括子类ReadLock和WriteLock。

首先来看一下ReadWriteLock接口中方法的定义:

  1. public interface ReadWriteLock {  
  2.     Lock readLock();  // 返回用于读取操作的锁  
  3.     Lock writeLock(); // 返回用于写入操作的锁  
  4. }  
public interface ReadWriteLock {
	Lock readLock();  // 返回用于读取操作的锁
	Lock writeLock(); // 返回用于写入操作的锁
}
读取锁和写入锁不可以同时存储,且读取锁可以同时存在多个,但是写入锁只能存在一个。
来看实现类中部分变量和方法,如下:

  1. private final ReentrantReadWriteLock.ReadLock readerLock; // 读锁  
  2. private final ReentrantReadWriteLock.WriteLock writerLock;// 写锁  
  3.   
  4. public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }  
  5. public ReentrantReadWriteLock.ReadLock  readLock()  { return readerLock; }  
  6.   
  7. // 默认为非公平锁  
  8. public ReentrantReadWriteLock() {  
  9.     this(false);  
  10. }  
  11. public ReentrantReadWriteLock(boolean fair) {  
  12.     sync = fair ? new FairSync() : new NonfairSync();  
  13.     readerLock = new ReadLock(this);  
  14.     writerLock = new WriteLock(this);  
  15. }  
    private final ReentrantReadWriteLock.ReadLock readerLock; // 读锁
    private final ReentrantReadWriteLock.WriteLock writerLock;// 写锁
    
    public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
    public ReentrantReadWriteLock.ReadLock  readLock()  { return readerLock; }

    // 默认为非公平锁
    public ReentrantReadWriteLock() {
        this(false);
    }
    public ReentrantReadWriteLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
        readerLock = new ReadLock(this);
        writerLock = new WriteLock(this);
    }

定义了读锁和写锁变量,同时提供了两个构造函数,用来构造公平或非公平锁。


1、获取共享读锁


ReadLock内部类的实现源代码如下:

  1. // 获取读锁,是共享锁  
  2. public static class ReadLock implements Lock, java.io.Serializable {  
  3.     private final Sync sync;  
  4.     protected ReadLock(ReentrantReadWriteLock lock) {  
  5.         sync = lock.sync;  
  6.     }  
  7.   
  8.     public void lock() { // 共享读锁的获取  
  9.         sync.acquireShared(1);  
  10.     }  
  11.   
  12.     //Acquires the read lock unless the current thread is interrupted.  
  13.     public void lockInterruptibly() throws InterruptedException {  
  14.         sync.acquireSharedInterruptibly(1);  
  15.     }  
  16.   
  17.     public  boolean tryLock() {  
  18.         return sync.tryReadLock();  
  19.     }  
  20.   
  21.     public boolean tryLock(long timeout, TimeUnit unit)  
  22.             throws InterruptedException {  
  23.         return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));  
  24.     }  
  25.   
  26.     public  void unlock() {  
  27.         sync.releaseShared(1);  
  28.     }  
  29.     public Condition newCondition() {  
  30.         throw new UnsupportedOperationException();  
  31.     }  
  32.     public String toString() {  
  33.         int r = sync.getReadLockCount();  
  34.         return super.toString() +  
  35.             "[Read locks = " + r + "]";  
  36.     }  
  37. }  
    // 获取读锁,是共享锁
    public static class ReadLock implements Lock, java.io.Serializable {
        private final Sync sync;
        protected ReadLock(ReentrantReadWriteLock lock) {
            sync = lock.sync;
        }

        public void lock() { // 共享读锁的获取
            sync.acquireShared(1);
        }

        //Acquires the read lock unless the current thread is interrupted.
        public void lockInterruptibly() throws InterruptedException {
            sync.acquireSharedInterruptibly(1);
        }

        public  boolean tryLock() {
            return sync.tryReadLock();
        }

        public boolean tryLock(long timeout, TimeUnit unit)
                throws InterruptedException {
            return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
        }

        public  void unlock() {
            sync.releaseShared(1);
        }
        public Condition newCondition() {
            throw new UnsupportedOperationException();
        }
        public String toString() {
            int r = sync.getReadLockCount();
            return super.toString() +
                "[Read locks = " + r + "]";
        }
    }

读取锁是通过调用lock()方法来获取的,在这个方法中调用了acquireShared()方法,这个方法在AQS中实现,如下:

  1. public final void acquireShared(int arg) {  
  2.     if (tryAcquireShared(arg) < 0)  
  3.         doAcquireShared(arg);  
  4. }  
public final void acquireShared(int arg) {
    if (tryAcquireShared(arg) < 0)
        doAcquireShared(arg);
}
前面已经多次碰到这相同代码,不解释,直接来看tryAcquireShared()方法的实现:

  1. protected final int tryAcquireShared(int unused) {  
  2.            Thread current = Thread.currentThread();  
  3.            int c = getState();        // 获取锁的状态  
  4.            // 如果锁是互斥锁,并且获取锁的线程不是当前线程,则返回-1,表示获取失败  
  5.            if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current)  
  6.                return -1;  
  7.            int r = sharedCount(c);     // 获取读取锁的共享计数  
  8.            // 如果不需要阻塞等待,并且读取锁的共享计数小于MAX_COUNT;  
  9.            // 则通过CAS函数更新锁的状态,将读取锁的共享计数+1。  
  10.            if (!readerShouldBlock() && r < MAX_COUNT && compareAndSetState(c, c + SHARED_UNIT)) {  
  11.                if (r == 0) {           // 第1次获取读取锁  
  12.                    firstReader = current;  
  13.                    firstReaderHoldCount = 1;  
  14.                // 如果想要获取锁的线程(current)是第1个获取锁(firstReader)的线程  
  15.                } else if (firstReader == current) {   
  16.                    firstReaderHoldCount++;  
  17.                } else {  
  18.                    // HoldCounter是用来统计该线程获取读取锁的次数。  
  19.                    HoldCounter rh = cachedHoldCounter;  
  20.                    if (rh == null || rh.tid != current.getId())  
  21.                        cachedHoldCounter = rh = readHolds.get();  
  22.                    else if (rh.count == 0)  
  23.                        readHolds.set(rh);  
  24.                    rh.count++;         // 将该线程获取读取锁的次数+1  
  25.                }  
  26.                return 1;  
  27.            }  
  28.            return fullTryAcquireShared(current);  
  29.        }  
 protected final int tryAcquireShared(int unused) {
            Thread current = Thread.currentThread();
            int c = getState();        // 获取锁的状态
            // 如果锁是互斥锁,并且获取锁的线程不是当前线程,则返回-1,表示获取失败
            if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current)
                return -1;
            int r = sharedCount(c);     // 获取读取锁的共享计数
            // 如果不需要阻塞等待,并且读取锁的共享计数小于MAX_COUNT;
            // 则通过CAS函数更新锁的状态,将读取锁的共享计数+1。
            if (!readerShouldBlock() && r < MAX_COUNT && compareAndSetState(c, c + SHARED_UNIT)) {
                if (r == 0) {           // 第1次获取读取锁
                    firstReader = current;
                    firstReaderHoldCount = 1;
                // 如果想要获取锁的线程(current)是第1个获取锁(firstReader)的线程
                } else if (firstReader == current) { 
                    firstReaderHoldCount++;
                } else {
                    // HoldCounter是用来统计该线程获取读取锁的次数。
                    HoldCounter rh = cachedHoldCounter;
                    if (rh == null || rh.tid != current.getId())
                        cachedHoldCounter = rh = readHolds.get();
                    else if (rh.count == 0)
                        readHolds.set(rh);
                    rh.count++;         // 将该线程获取读取锁的次数+1
                }
                return 1;
            }
            return fullTryAcquireShared(current);
        }
tryAcquireShared()的作用是尝试获取共享锁,如果通过如上的方法获取失败,则调用fullTryAcquireShared()方法来获取:

  1. final int fullTryAcquireShared(Thread current) {  
  2.             HoldCounter rh = null;  
  3.             for (;;) {  
  4.                 int c = getState();                           // 获取锁的状态  
  5.                 if (exclusiveCount(c) != 0) {                 // 写线程获取互斥锁   
  6.                     if (getExclusiveOwnerThread() != current) // 获取锁的线程不是当前线程  
  7.                         return -1;  
  8.                 } else if (readerShouldBlock()) { // 需要阻塞等待  
  9.                     if (firstReader == current) { // 当前线程是第一个线程  
  10.                     } else {  
  11.                         if (rh == null) {  
  12.                             rh = cachedHoldCounter;  
  13.                             if (rh == null || rh.tid != current.getId()) {  
  14.                                 rh = readHolds.get();  
  15.                                 if (rh.count == 0)  
  16.                                     readHolds.remove();  
  17.                             }  
  18.                         }  
  19.                         if (rh.count == 0)// 如果当前线程获取锁的计数为0,则返回-1。  
  20.                             return -1;  
  21.                     }  
  22.                 }  
  23.                 // 不需要阻塞等待,获取读取锁的共享统计数;如果共享统计数超过MAX_COUNT,则抛出异常  
  24.                 if (sharedCount(c) == MAX_COUNT)  
  25.                     throw new Error("Maximum lock count exceeded");  
  26.                 // 将线程获取读取锁的次数加1。  
  27.                 if (compareAndSetState(c, c + SHARED_UNIT)) {  
  28.                     // 如果是第1次获取“读取锁”,则更新firstReader和firstReaderHoldCount。  
  29.                     if (sharedCount(c) == 0) {  
  30.                         firstReader = current;  
  31.                         firstReaderHoldCount = 1;  
  32.                     // 如果想要获取锁的线程(current)是第1个获取锁(firstReader)的线程,  
  33.                     // 则将firstReaderHoldCount+1。  
  34.                     } else if (firstReader == current) {  
  35.                         firstReaderHoldCount++;  
  36.                     } else {  
  37.                         if (rh == null)  
  38.                             rh = cachedHoldCounter;  
  39.                         if (rh == null || rh.tid != current.getId())  
  40.                             rh = readHolds.get();  
  41.                         else if (rh.count == 0)  
  42.                             readHolds.set(rh);  
  43.                         // 更新线程的获取“读取锁”的共享计数  
  44.                         rh.count++;  
  45.                         cachedHoldCounter = rh; // cache for release  
  46.                     }  
  47.                     return 1;  
  48.                 }  
  49.             }  
  50.         }  
final int fullTryAcquireShared(Thread current) {
            HoldCounter rh = null;
            for (;;) {
                int c = getState();                           // 获取锁的状态
                if (exclusiveCount(c) != 0) {                 // 写线程获取互斥锁 
                    if (getExclusiveOwnerThread() != current) // 获取锁的线程不是当前线程
                        return -1;
                } else if (readerShouldBlock()) { // 需要阻塞等待
                    if (firstReader == current) { // 当前线程是第一个线程
                    } else {
                        if (rh == null) {
                            rh = cachedHoldCounter;
                            if (rh == null || rh.tid != current.getId()) {
                                rh = readHolds.get();
                                if (rh.count == 0)
                                    readHolds.remove();
                            }
                        }
                        if (rh.count == 0)// 如果当前线程获取锁的计数为0,则返回-1。
                            return -1;
                    }
                }
                // 不需要阻塞等待,获取读取锁的共享统计数;如果共享统计数超过MAX_COUNT,则抛出异常
                if (sharedCount(c) == MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                // 将线程获取读取锁的次数加1。
                if (compareAndSetState(c, c + SHARED_UNIT)) {
                    // 如果是第1次获取“读取锁”,则更新firstReader和firstReaderHoldCount。
                    if (sharedCount(c) == 0) {
                        firstReader = current;
                        firstReaderHoldCount = 1;
                    // 如果想要获取锁的线程(current)是第1个获取锁(firstReader)的线程,
                    // 则将firstReaderHoldCount+1。
                    } else if (firstReader == current) {
                        firstReaderHoldCount++;
                    } else {
                        if (rh == null)
                            rh = cachedHoldCounter;
                        if (rh == null || rh.tid != current.getId())
                            rh = readHolds.get();
                        else if (rh.count == 0)
                            readHolds.set(rh);
                        // 更新线程的获取“读取锁”的共享计数
                        rh.count++;
                        cachedHoldCounter = rh; // cache for release
                    }
                    return 1;
                }
            }
        }
doAcquireShared()定义在AQS函数中,源码如下:

  1. private void doAcquireShared(int arg) {  
  2.     final Node node = addWaiter(Node.SHARED);  
  3.     boolean failed = true;  
  4.     try {  
  5.         boolean interrupted = false;  
  6.         for (;;) {  
  7.             final Node p = node.predecessor();  
  8.             if (p == head) {  
  9.                 int r = tryAcquireShared(arg);  
  10.                 if (r >= 0) {  
  11.                     setHeadAndPropagate(node, r);  
  12.                     p.next = null// help GC  
  13.                     if (interrupted)  
  14.                         selfInterrupt();  
  15.                     failed = false;  
  16.                     return;  
  17.                 }  
  18.             }  
  19.             if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())  
  20.                 interrupted = true;  
  21.         }  
  22.     } finally {  
  23.         if (failed)  
  24.             cancelAcquire(node);  
  25.     }  
  26. }  
private void doAcquireShared(int arg) {
    final Node node = addWaiter(Node.SHARED);
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            final Node p = node.predecessor();
            if (p == head) {
                int r = tryAcquireShared(arg);
                if (r >= 0) {
                    setHeadAndPropagate(node, r);
                    p.next = null; // help GC
                    if (interrupted)
                        selfInterrupt();
                    failed = false;
                    return;
                }
            }
            if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}
这段代码与前面的实现相同,在此不估过多的解释。

2、释放共享读锁


调用ReadLock中的unlock()方法来释放共享读锁,在这个方法中调用了如下的方法:

  1. public final boolean releaseShared(int arg) {  
  2.         if (tryReleaseShared(arg)) {  
  3.             doReleaseShared();  
  4.             return true;  
  5.         }  
  6.         return false;  
  7.     }  
public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }
  1. protected final boolean tryReleaseShared(int unused) {  
  2.            // 获取当前线程,即释放共享锁的线程  
  3.            Thread current = Thread.currentThread();  
  4.            // 如果想要释放锁的线程(current)是第1个获取锁(firstReader)的线程,  
  5.            // 并且第1个获取锁的线程获取锁的次数=1,则设置firstReader为null;  
  6.            // 否则,将第1个获取锁的线程的获取次数-1。  
  7.            if (firstReader == current) {  
  8.                // assert firstReaderHoldCount > 0;  
  9.                if (firstReaderHoldCount == 1)  
  10.                    firstReader = null;  
  11.                else  
  12.                    firstReaderHoldCount--;  
  13.            } else {  
  14.             // 获取rh对象,并更新当前线程获取锁的信息  
  15.                HoldCounter rh = cachedHoldCounter;  
  16.                if (rh == null || rh.tid != current.getId())  
  17.                    rh = readHolds.get();  
  18.                int count = rh.count;  
  19.                if (count <= 1) {  
  20.                    readHolds.remove();  
  21.                    if (count <= 0)  
  22.                        throw unmatchedUnlockException();  
  23.                }  
  24.                --rh.count;  
  25.            }  
  26.            for (;;) {  
  27.                int c = getState();         // 获取锁的状态  
  28.                int nextc = c - SHARED_UNIT;// 将锁的获取次数-1  
  29.                // 通过CAS更新锁的状态  
  30.                if (compareAndSetState(c, nextc))  
  31.                    return nextc == 0;  
  32.            }  
  33.        }  
 protected final boolean tryReleaseShared(int unused) {
            // 获取当前线程,即释放共享锁的线程
            Thread current = Thread.currentThread();
            // 如果想要释放锁的线程(current)是第1个获取锁(firstReader)的线程,
            // 并且第1个获取锁的线程获取锁的次数=1,则设置firstReader为null;
            // 否则,将第1个获取锁的线程的获取次数-1。
            if (firstReader == current) {
                // assert firstReaderHoldCount > 0;
                if (firstReaderHoldCount == 1)
                    firstReader = null;
                else
                    firstReaderHoldCount--;
            } else {
            	// 获取rh对象,并更新当前线程获取锁的信息
                HoldCounter rh = cachedHoldCounter;
                if (rh == null || rh.tid != current.getId())
                    rh = readHolds.get();
                int count = rh.count;
                if (count <= 1) {
                    readHolds.remove();
                    if (count <= 0)
                        throw unmatchedUnlockException();
                }
                --rh.count;
            }
            for (;;) {
                int c = getState();         // 获取锁的状态
                int nextc = c - SHARED_UNIT;// 将锁的获取次数-1
                // 通过CAS更新锁的状态
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }


  1. private void doReleaseShared() {  
  2.     for (;;) {  
  3.         // 获取CLH队列的头节点  
  4.         Node h = head;  
  5.         // 如果头节点不为null,并且头节点不等于tail节点。  
  6.         if (h != null && h != tail) {  
  7.             // 获取头节点对应的线程的状态  
  8.             int ws = h.waitStatus;  
  9.             // 如果头节点对应的线程是SIGNAL状态,则意味着“头节点的下一个节点所对应的线程”需要被unpark唤醒。  
  10.             if (ws == Node.SIGNAL) {  
  11.                 // 设置“头节点对应的线程状态”为空状态。失败的话,则继续循环。  
  12.                 if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))  
  13.                     continue;  
  14.                 // 唤醒“头节点的下一个节点所对应的线程”。  
  15.                 unparkSuccessor(h);  
  16.             }  
  17.             // 如果头节点对应的线程是空状态,则设置“文件点对应的线程所拥有的共享锁”为其它线程获取锁的空状态。  
  18.             else if (ws == 0 &&  
  19.                      !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))  
  20.                 continue;                // loop on failed CAS  
  21.         }  
  22.         // 如果头节点发生变化,则继续循环。否则,退出循环。  
  23.         if (h == head)                   // loop if head changed  
  24.             break;  
  25.     }  
  26. }  
private void doReleaseShared() {
    for (;;) {
        // 获取CLH队列的头节点
        Node h = head;
        // 如果头节点不为null,并且头节点不等于tail节点。
        if (h != null && h != tail) {
            // 获取头节点对应的线程的状态
            int ws = h.waitStatus;
            // 如果头节点对应的线程是SIGNAL状态,则意味着“头节点的下一个节点所对应的线程”需要被unpark唤醒。
            if (ws == Node.SIGNAL) {
                // 设置“头节点对应的线程状态”为空状态。失败的话,则继续循环。
                if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                    continue;
                // 唤醒“头节点的下一个节点所对应的线程”。
                unparkSuccessor(h);
            }
            // 如果头节点对应的线程是空状态,则设置“文件点对应的线程所拥有的共享锁”为其它线程获取锁的空状态。
            else if (ws == 0 &&
                     !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                continue;                // loop on failed CAS
        }
        // 如果头节点发生变化,则继续循环。否则,退出循环。
        if (h == head)                   // loop if head changed
            break;
    }
}


3、读取锁的公正锁和非公平锁

公平锁和非公平锁的区别,体现在判断是否需要阻塞的函数readerShouldBlock()是不同的。公平锁的readerShouldBlock()的源码如下:

  1. final boolean readerShouldBlock() {  
  2.     return hasQueuedPredecessors();  
  3. }  
final boolean readerShouldBlock() {
    return hasQueuedPredecessors();
}
在公平共享锁中,如果在当前线程的前面有其他线程在等待获取共享锁,则返回true;否则,返回false。
非公平锁的readerShouldBlock()的源码如下:
  1. final boolean readerShouldBlock() {  
  2.     return apparentlyFirstQueuedIsExclusive();  
  3. }  
final boolean readerShouldBlock() {
    return apparentlyFirstQueuedIsExclusive();
}
在非公平共享锁中,它会无视当前线程的前面是否有其他线程在等待获取共享锁。只要该非公平共享锁对应的线程不为null,则返回true


4、举例


  1. public class ReadWriteLockTest1 {   
  2.   
  3.     public static void main(String[] args) {   
  4.         // 创建账户  
  5.         MyCount myCount = new MyCount("4238920615242830"10000);   
  6.         // 创建用户,并指定账户  
  7.         User user = new User("Tommy", myCount);   
  8.         // 分别启动3个“读取账户金钱”的线程 和 3个“设置账户金钱”的线程  
  9.         for (int i=0; i<3; i++) {  
  10.             user.getCash();  
  11.             user.setCash((i+1)*1000);  
  12.         }  
  13.     }   
  14. }   
  15.   
  16. class User {  
  17.     private String name;            //用户名   
  18.     private MyCount myCount;        //所要操作的账户   
  19.     private ReadWriteLock myLock;   //执行操作所需的锁对象   
  20.   
  21.     User(String name, MyCount myCount) {  
  22.         this.name = name;   
  23.         this.myCount = myCount;   
  24.         this.myLock = new ReentrantReadWriteLock();  
  25.     }  
  26.   
  27.     public void getCash() {  
  28.         new Thread() {  
  29.             public void run() {  
  30.                 myLock.readLock().lock();   
  31.                 try {  
  32.                     System.out.println(Thread.currentThread().getName() +" getCash start");   
  33.                     myCount.getCash();  
  34.                     Thread.sleep(1);  
  35.                     System.out.println(Thread.currentThread().getName() +" getCash end");   
  36.                 } catch (InterruptedException e) {  
  37.                 } finally {  
  38.                     myLock.readLock().unlock();   
  39.                 }  
  40.             }  
  41.         }.start();  
  42.     }  
  43.   
  44.     public void setCash(final int cash) {  
  45.         new Thread() {  
  46.             public void run() {  
  47.                 myLock.writeLock().lock();   
  48.                 try {  
  49.                     System.out.println(Thread.currentThread().getName() +" setCash start");   
  50.                     myCount.setCash(cash);  
  51.                     Thread.sleep(1);  
  52.                     System.out.println(Thread.currentThread().getName() +" setCash end");   
  53.                 } catch (InterruptedException e) {  
  54.                 } finally {  
  55.                     myLock.writeLock().unlock();   
  56.                 }  
  57.             }  
  58.         }.start();  
  59.     }  
  60. }  
  61.   
  62. class MyCount {  
  63.     private String id;         //账号   
  64.     private int    cash;       //账户余额   
  65.   
  66.     MyCount(String id, int cash) {   
  67.         this.id = id;   
  68.         this.cash = cash;   
  69.     }   
  70.   
  71.     public String getId() {   
  72.         return id;   
  73.     }   
  74.   
  75.     public void setId(String id) {   
  76.         this.id = id;   
  77.     }   
  78.   
  79.     public int getCash() {   
  80.         System.out.println(Thread.currentThread().getName() +" getCash cash="+ cash);   
  81.         return cash;   
  82.     }   
  83.   
  84.     public void setCash(int cash) {   
  85.         System.out.println(Thread.currentThread().getName() +" setCash cash="+ cash);   
  86.         this.cash = cash;   
  87.     }   
  88. }  
public class ReadWriteLockTest1 { 

    public static void main(String[] args) { 
        // 创建账户
        MyCount myCount = new MyCount("4238920615242830", 10000); 
        // 创建用户,并指定账户
        User user = new User("Tommy", myCount); 
        // 分别启动3个“读取账户金钱”的线程 和 3个“设置账户金钱”的线程
        for (int i=0; i<3; i++) {
            user.getCash();
            user.setCash((i+1)*1000);
        }
    } 
} 

class User {
    private String name;            //用户名 
    private MyCount myCount;        //所要操作的账户 
    private ReadWriteLock myLock;   //执行操作所需的锁对象 

    User(String name, MyCount myCount) {
        this.name = name; 
        this.myCount = myCount; 
        this.myLock = new ReentrantReadWriteLock();
    }

    public void getCash() {
        new Thread() {
            public void run() {
                myLock.readLock().lock(); 
                try {
                    System.out.println(Thread.currentThread().getName() +" getCash start"); 
                    myCount.getCash();
                    Thread.sleep(1);
                    System.out.println(Thread.currentThread().getName() +" getCash end"); 
                } catch (InterruptedException e) {
                } finally {
                    myLock.readLock().unlock(); 
                }
            }
        }.start();
    }

    public void setCash(final int cash) {
        new Thread() {
            public void run() {
                myLock.writeLock().lock(); 
                try {
                    System.out.println(Thread.currentThread().getName() +" setCash start"); 
                    myCount.setCash(cash);
                    Thread.sleep(1);
                    System.out.println(Thread.currentThread().getName() +" setCash end"); 
                } catch (InterruptedException e) {
                } finally {
                    myLock.writeLock().unlock(); 
                }
            }
        }.start();
    }
}

class MyCount {
    private String id;         //账号 
    private int    cash;       //账户余额 

    MyCount(String id, int cash) { 
        this.id = id; 
        this.cash = cash; 
    } 

    public String getId() { 
        return id; 
    } 

    public void setId(String id) { 
        this.id = id; 
    } 

    public int getCash() { 
        System.out.println(Thread.currentThread().getName() +" getCash cash="+ cash); 
        return cash; 
    } 

    public void setCash(int cash) { 
        System.out.println(Thread.currentThread().getName() +" setCash cash="+ cash); 
        this.cash = cash; 
    } 
}
运行的结果如下:

  1. Thread-0 getCash start  
  2. Thread-2 getCash start  
  3. Thread-0 getCash cash=10000  
  4. Thread-2 getCash cash=10000  
  5. Thread-0 getCash end  
  6. Thread-2 getCash end  
  7. Thread-1 setCash start  
  8. Thread-1 setCash cash=1000  
  9. Thread-1 setCash end  
  10. Thread-3 setCash start  
  11. Thread-3 setCash cash=2000  
  12. Thread-3 setCash end  
  13. Thread-4 getCash start  
  14. Thread-4 getCash cash=2000  
  15. Thread-4 getCash end  
  16. Thread-5 setCash start  
  17. Thread-5 setCash cash=3000  
  18. Thread-5 setCash end  
Thread-0 getCash start
Thread-2 getCash start
Thread-0 getCash cash=10000
Thread-2 getCash cash=10000
Thread-0 getCash end
Thread-2 getCash end
Thread-1 setCash start
Thread-1 setCash cash=1000
Thread-1 setCash end
Thread-3 setCash start
Thread-3 setCash cash=2000
Thread-3 setCash end
Thread-4 getCash start
Thread-4 getCash cash=2000
Thread-4 getCash end
Thread-5 setCash start
Thread-5 setCash cash=3000
Thread-5 setCash end



转载自http://blog.youkuaiyun.com/mazhimazh/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值