Ò»¡¢
¸ÅÊö
±¾ÎÄÊ×ÏȽéÉÜLock½Ó¿Ú¡¢ReentrantLockµÄÀà²ã´Î½á¹¹ÒÔ¼°Ëø¹¦ÄÜÄ£°åÀàAbstractQueuedSynchronizerµÄ¼òµ¥ÔÀí£¬È»ºóͨ¹ý·ÖÎöReentrantLockµÄlock·½·¨ºÍunlock·½·¨£¬À´½âÊÍReentrantLockµÄÄÚ²¿ÔÀí£¬×îºó×öÒ»¸ö×ܽᡣ±¾ÎIJ»Éæ¼°ReentrantLockÖеÄÌõ¼þ±äÁ¿¡£
1.1¡¢Lock½Ó¿Ú
Lock½Ó¿Ú£¬ÊǶԿØÖƲ¢·¢µÄ¹¤¾ßµÄ³éÏó¡£Ëü±ÈʹÓÃsynchronized¹Ø¼ü´Ê¸üÁé»î£¬²¢ÇÒÄܹ»Ö§³ÖÌõ¼þ±äÁ¿¡£ËüÊÇÒ»ÖÖ¿ØÖƲ¢·¢µÄ¹¤¾ß£¬Ò»°ãÀ´Ëµ£¬Ëü¿ØÖƶÔijÖÖ¹²Ïí×ÊÔ´µÄ¶ÀÕ¼¡£Ò²¾ÍÊÇ˵£¬Í¬Ò»Ê±¼äÄÚÖ»ÓÐÒ»¸öÏ߳̿ÉÒÔ»ñÈ¡Õâ¸öËø²¢Õ¼ÓÃ×ÊÔ´¡£ÆäËûÏß³ÌÏëÒª»ñÈ¡Ëø£¬±ØÐëµÈ´ýÕâ¸öÏß³ÌÊÍ·ÅËø¡£ÔÚJavaʵÏÖÖеÄReentrantLock¾ÍÊÇÕâÑùµÄËø¡£ÁíÍâÒ»ÖÖËø£¬Ëü¿ÉÒÔÔÊÐí¶à¸öÏ̶߳ÁÈ¡×ÊÔ´£¬µ«ÊÇÖ»ÄÜÔÊÐíÒ»¸öÏß³ÌдÈë×ÊÔ´£¬ReadWriteLock¾ÍÊÇÕâÑùÒ»ÖÖÌØÊâµÄËø£¬¼ò³Æ¶ÁÐ´Ëø¡£ÏÂÃæÊǶÔLock½Ó¿ÚµÄ¼¸¸ö·½·¨µÄ×ÜÌåÃèÊö£º

½ÓÏÂÀ´£¬ÎÒÃǽ«Î§ÈÆlockºÍunlockÕâÁ½¸ö·½·¨£¬À´½éÉÜÕû¸öReentrantLockÊÇÔõô¹¤×÷µÄ¡£ÔÚ½éÉÜReentrantLock֮ǰ£¬ÎÒÃÇÊ×ÏÈÀ´¿´Ò»ÏÂReentrantLockµÄÀà²ã´Î½á¹¹ÒÔ¼°ºÍËüÃÜÇÐÏà¹ØµÄAbstractQueuedSynchronizer
1.2¡¢ReentrantLockÀà²ã´Î½á¹¹

ReentrantLockʵÏÖÁËLock½Ó¿Ú£¬ÄÚ²¿ÓÐÈý¸öÄÚ²¿À࣬Sync¡¢NonfairSync¡¢FairSync£¬SyncÊÇÒ»¸ö³éÏóÀàÐÍ£¬Ëü¼Ì³ÐAbstractQueuedSynchronizer£¬Õâ¸öAbstractQueuedSynchronizerÊÇÒ»¸öÄ£°åÀ࣬ËüʵÏÖÁËÐí¶àºÍËøÏà¹ØµÄ¹¦ÄÜ£¬²¢ÌṩÁ˹³×Ó·½·¨¹©Óû§ÊµÏÖ£¬±ÈÈçtryAcquire£¬tryReleaseµÈ¡£SyncʵÏÖÁËAbstractQueuedSynchronizerµÄtryRelease·½·¨¡£NonfairSyncºÍFairSyncÁ½¸öÀà¼Ì³Ð×ÔSync£¬ÊµÏÖÁËlock·½·¨£¬È»ºó·Ö±ð¹«Æ½ÇÀÕ¼ºÍ·Ç¹«Æ½ÇÀÕ¼Õë¶ÔtryAcquireÓв»Í¬µÄʵÏÖ¡£
1.3¡¢AbstractQueuedSynchronizer
Ê×ÏÈ£¬AbstractQueuedSynchronizer¼Ì³Ð×ÔAbstractOwnableSynchronizer£¬AbstractOwnableSynchronizerµÄʵÏֺܼòµ¥£¬Ëü±íʾ¶ÀÕ¼µÄͬ²½Æ÷£¬ÄÚ²¿Ê¹ÓñäÁ¿exclusiveOwnerThread±íʾ¶ÀÕ¼µÄÏ̡߳£
Æä´Î£¬AbstractQueuedSynchronizerÄÚ²¿Ê¹ÓÃCLHËø¶ÓÁÐÀ´½«²¢·¢Ö´Ðбä³É´®ÐÐÖ´ÐС£Õû¸ö¶ÓÁÐÊÇÒ»¸öË«ÏòÁ´±í¡£Ã¿¸öCLHËø¶ÓÁеĽڵ㣬»á±£´æÇ°Ò»¸ö½ÚµãºÍºóÒ»¸ö½ÚµãµÄÒýÓ㬵±Ç°½Úµã¶ÔÓ¦µÄỊ̈߳¬ÒÔ¼°Ò»¸ö״̬¡£Õâ¸ö״̬ÓÃÀ´±íÃ÷¸ÃÏß³ÌÊÇ·ñÓ¦¸Ãblock¡£µ±½ÚµãµÄǰһ¸ö½Úµã±»ÊͷŵÄʱºò£¬µ±Ç°½Úµã¾Í±»»½ÐÑ£¬³ÉΪͷ²¿¡£Ð¼ÓÈëµÄ½Úµã»á·ÅÔÚ¶ÓÁÐβ²¿¡£
¶þ¡¢ ·Ç¹«Æ½ËøµÄlock·½·¨
2.1¡¢lock·½·¨Á÷³Ìͼ

2.2¡¢lock·½·¨ÏêϸÃèÊö
1¡¢ÔÚ³õʼ»¯ReentrantLockµÄʱºò£¬Èç¹ûÎÒÃDz»´«²ÎÊýÊÇ·ñ¹«Æ½£¬ÄÇôĬÈÏʹÓ÷ǹ«Æ½Ëø£¬Ò²¾ÍÊÇNonfairSync¡£
2¡¢µ±ÎÒÃǵ÷ÓÃReentrantLockµÄlock·½·¨µÄʱºò£¬Êµ¼ÊÉÏÊǵ÷ÓÃÁËNonfairSyncµÄlock·½·¨£¬Õâ¸ö·½·¨ÏÈÓÃCAS²Ù×÷£¬È¥³¢ÊÔÇÀÕ¼¸ÃËø¡£Èç¹û³É¹¦£¬¾Í°Ñµ±Ç°Ïß³ÌÉèÖÃÔÚÕâ¸öËøÉÏ£¬±íʾÇÀÕ¼³É¹¦¡£Èç¹ûʧ°Ü£¬Ôòµ÷ÓÃacquireÄ£°å·½·¨£¬µÈ´ýÇÀÕ¼¡£´úÂëÈçÏ£º
static final class NonfairSync extends Sync { final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }
protected final boolean tryAcquire(int acquires)
{
return nonfairTryAcquire(acquires);
}
} |
3¡¢µ÷ÓÃacquire(1)ʵ¼ÊÉÏʹÓõÄÊÇAbstractQueuedSynchronizerµÄacquire·½·¨£¬ËüÊÇÒ»Ì×ËøÇÀÕ¼µÄÄ£°å£¬×ÜÌåÔÀíÊÇÏÈÈ¥³¢ÊÔ»ñÈ¡Ëø£¬Èç¹ûûÓлñÈ¡³É¹¦£¬¾ÍÔÚCLH¶ÓÁÐÖÐÔö¼ÓÒ»¸öµ±Ç°Ï̵߳Ľڵ㣬±íʾµÈ´ýÇÀÕ¼¡£È»ºó½øÈëCLH¶ÓÁеÄÇÀռģʽ£¬½øÈëµÄʱºòÒ²»áÈ¥Ö´ÐÐÒ»´Î»ñÈ¡ËøµÄ²Ù×÷£¬Èç¹û»¹ÊÇ»ñÈ¡²»µ½£¬¾Íµ÷ÓÃLockSupport.park½«µ±Ç°Ïß³Ì¹ÒÆð¡£ÄÇôµ±Ç°Ïß³Ìʲôʱºò»á±»»½ÐÑÄØ£¿µ±³ÖÓÐËøµÄÄǸöÏ̵߳÷ÓÃunlockµÄʱºò£¬»á½«CLH¶ÓÁеÄÍ·½ÚµãµÄÏÂÒ»¸ö½ÚµãÉϵÄÏ̻߳½ÐÑ£¬µ÷ÓõÄÊÇLockSupport.unpark·½·¨¡£acquire´úÂë±È½Ï¼òµ¥£¬¾ßÌåÈçÏ£º
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } |
3.1¡¢acquire·½·¨ÄÚ²¿ÏÈʹÓÃtryAcquireÕâ¸ö¹³×Ó·½·¨È¥³¢ÊÔÔٴλñÈ¡Ëø£¬Õâ¸ö·½·¨ÔÚNonfairSyncÕâ¸öÀàÖÐÆäʵ¾ÍÊÇʹÓÃÁËnonfairTryAcquire£¬¾ßÌåʵÏÖÔÀíÊÇÏȱȽϵ±Ç°ËøµÄ״̬ÊÇ·ñÊÇ0£¬Èç¹ûÊÇ0£¬Ôò³¢ÊÔÈ¥Ô×ÓÇÀÕ¼Õâ¸öËø£¨ÉèÖÃ״̬Ϊ1£¬È»ºó°Ñµ±Ç°Ïß³ÌÉèÖóɶÀÕ¼Ị̈߳©£¬Èç¹ûµ±Ç°ËøµÄ״̬²»ÊÇ0£¬¾ÍÈ¥±È½Ïµ±Ç°Ï̺߳ÍÕ¼ÓÃËøµÄÏß³ÌÊDz»ÊÇÒ»¸öỊ̈߳¬Èç¹ûÊÇ£¬»áÈ¥Ôö¼Ó״̬±äÁ¿µÄÖµ£¬´ÓÕâÀï¿´³ö¿ÉÖØÈëËøÖ®ËùÒÔ¿ÉÖØÈ룬¾ÍÊÇͬһ¸öÏ߳̿ÉÒÔ·´¸´Ê¹ÓÃËüÕ¼ÓõÄËø¡£Èç¹ûÒÔÉÏÁ½ÖÖÇé¿ö¶¼²»Í¨¹ý£¬Ôò·µ»ØÊ§°Üfalse¡£´úÂëÈçÏ£º
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; } |
3.2¡¢tryAcquireÒ»µ©·µ»Øfalse£¬¾Í»áÔò½øÈëacquireQueuedÁ÷³Ì£¬Ò²¾ÍÊÇ»ùÓÚCLH¶ÓÁеÄÇÀռģʽ£º
3.2.1¡¢Ê×ÏÈ£¬ÔÚCLHËø¶ÓÁÐβ²¿Ôö¼ÓÒ»¸öµÈ´ý½Úµã£¬Õâ¸ö½Úµã±£´æÁ˵±Ç°Ị̈߳¬Í¨¹ýµ÷ÓÃaddWaiterʵÏÖ£¬ÕâÀïÐèÒª¿¼Âdzõʼ»¯µÄÇé¿ö£¬ÔÚµÚÒ»¸öµÈ´ý½Úµã½øÈëµÄʱºò£¬ÐèÒª³õʼ»¯Ò»¸öÍ·½ÚµãÈ»ºó°Ñµ±Ç°½Úµã¼ÓÈ뵽β²¿£¬ºóÐøÔòÖ±½ÓÔÚβ²¿¼ÓÈë½Úµã¾ÍÐÐÁË¡£
´úÂëÈçÏ£º
private Node addWaiter(Node mode) { // ³õʼ»¯Ò»¸ö½Úµã£¬Õâ¸ö½Úµã±£´æµ±Ç°Ïß³Ì Node node = new Node(Thread.currentThread(), mode); // µ±CLH¶ÓÁв»Îª¿ÕµÄÊÓºõ£¬Ö±½ÓÔÚ¶ÓÁÐβ²¿²åÈëÒ»¸ö½Úµã Node pred = tail; if (pred != null) { node.prev = pred; if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } // µ±CLH¶ÓÁÐΪ¿ÕµÄʱºò£¬µ÷ÓÃenq·½·¨³õʼ»¯¶ÓÁÐ enq(node); return node; }
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // ³õʼ»¯½Úµã£¬Í·Î²¶¼Ö¸ÏòÒ»¸ö¿Õ½Úµã
if (compareAndSetHead(new Node()))
tail = head;
} else {// ¿¼ÂDz¢·¢³õʼ»¯
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
} |
3.2.2¡¢½«½ÚµãÔö¼Óµ½CLH¶ÓÁк󣬽øÈëacquireQueued·½·¨¡£
Ê×ÏÈ£¬Íâ²ãÊÇÒ»¸öÎÞÏÞforÑ»·£¬Èç¹ûµ±Ç°½ÚµãÊÇÍ·½ÚµãµÄϸö½Úµã£¬²¢ÇÒͨ¹ýtryAcquire»ñÈ¡µ½ÁËËø£¬ËµÃ÷Í·½ÚµãÒѾÊÍ·ÅÁËËø£¬µ±Ç°Ïß³ÌÊDZ»Í·½ÚµãÄǸöÏ̻߳½Ðѵģ¬Õâʱºò¾Í¿ÉÒÔ½«µ±Ç°½ÚµãÉèÖóÉÍ·½Úµã£¬²¢ÇÒ½«failed±ê¼ÇÉèÖóÉfalse£¬È»ºó·µ»Ø¡£ÖÁÓÚÉÏÒ»¸ö½Úµã£¬ËüµÄnext±äÁ¿±»ÉèÖÃΪnull£¬ÔÚÏ´ÎGCµÄʱºò»áÇåÀíµô¡£
Èç¹û±¾´ÎÑ»·Ã»ÓлñÈ¡µ½Ëø£¬¾Í½øÈëÏß³Ì¹ÒÆð½×¶Î£¬Ò²¾ÍÊÇshouldParkAfterFailedAcquireÕâ¸ö·½·¨¡£
´úÂëÈçÏ£º
final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return interrupted; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } } |
3.2.3¡¢Èç¹û³¢ÊÔ»ñÈ¡ËøÊ§°Ü£¬¾Í»á½øÈëshouldParkAfterFailedAcquire·½·¨£¬»áÅжϵ±Ç°Ïß³ÌÊÇ·ñ¹ÒÆð£¬Èç¹ûǰһ¸ö½ÚµãÒѾÊÇSIGNAL״̬£¬Ôòµ±Ç°Ïß³ÌÐèÒª¹ÒÆð¡£Èç¹ûǰһ¸ö½ÚµãÊÇÈ¡Ïû״̬£¬ÔòÐèÒª½«È¡Ïû½Úµã´Ó¶ÓÁÐÒÆ³ý¡£Èç¹ûǰһ¸ö½Úµã״̬ÊÇÆäËû״̬£¬Ôò³¢ÊÔÉèÖóÉSIGNAL״̬£¬²¢·µ»Ø²»ÐèÒª¹ÒÆð£¬´Ó¶ø½øÐеڶþ´ÎÇÀÕ¼¡£Íê³ÉÉÏÃæµÄʺó½øÈë¹ÒÆð½×¶Î¡£
´úÂëÈçÏ£º
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { int ws = pred.waitStatus; if (ws == Node.SIGNAL) // return true; if (ws > 0) { // do { node.prev = pred = pred.prev; } while (pred.waitStatus > 0); pred.next = node; } else { // compareAndSetWaitStatus(pred, ws, Node.SIGNAL); } return false; } |
3.2.4¡¢µ±½øÈë¹ÒÆð½×¶Î£¬»á½øÈëparkAndCheckInterrupt·½·¨£¬Ôò»áµ÷ÓÃLockSupport.park(this)½«µ±Ç°Ïß³Ì¹ÒÆð¡£´úÂë
£º
private final boolean parkAndCheckInterrupt() { LockSupport.park(this); return Thread.interrupted(); } |
Èý¡¢ ·Ç¹«Æ½ËøµÄunlock·½·¨
3.1¡¢unlock·½·¨µÄ»î¶¯Í¼

3.2¡¢unlock·½·¨ÏêϸÃèÊö
1¡¢µ÷ÓÃunlock·½·¨£¬ÆäʵÊÇÖ±½Óµ÷ÓÃAbstractQueuedSynchronizerµÄrelease²Ù×÷¡£
2¡¢½øÈërelease·½·¨£¬ÄÚ²¿Ïȳ¢ÊÔtryRelease²Ù×÷,Ö÷ÒªÊÇÈ¥³ýËøµÄ¶ÀÕ¼Ị̈߳¬È»ºó½«×´Ì¬¼õÒ»£¬ÕâÀï¼õÒ»Ö÷ÒªÊÇ¿¼Âǵ½¿ÉÖØÈëËø¿ÉÄÜ×ÔÉí»á¶à´ÎÕ¼ÓÃËø£¬Ö»Óе±×´Ì¬±ä³É0£¬²Å±íʾÍêÈ«ÊÍ·ÅÁËËø¡£
3¡¢Ò»µ©tryRelease³É¹¦£¬Ôò½«CHL¶ÓÁеÄÍ·½ÚµãµÄ״̬ÉèÖÃΪ0£¬È»ºó»½ÐÑÏÂÒ»¸ö·ÇÈ¡ÏûµÄ½ÚµãÏ̡߳£
4¡¢Ò»µ©ÏÂÒ»¸ö½ÚµãµÄÏ̱߳»»½ÐÑ£¬±»»½ÐѵÄÏß³Ì¾Í»á½øÈëacquireQueued´úÂëÁ÷³ÌÖУ¬È¥»ñÈ¡Ëø¡£
¾ßÌå´úÂëÈçÏ£º
unlock´úÂ룺
public void unlock() { sync.release(1); } |
release·½·¨´úÂ룺
public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; } |
SyncÖÐͨÓõÄtryRelease·½·¨´úÂ룺
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; }! |
unparkSuccessor´úÂ룺
private void unparkSuccessor(Node node) { int ws = node.waitStatus; if (ws < 0) compareAndSetWaitStatus(node, ws, 0); Node s = node.next; if (s == null || s.waitStatus > 0) { s = null; for (Node t = tail; t != null && t != node; t = t.prev) if (t.waitStatus <= 0) s = t; } if (s != null) LockSupport.unpark(s.thread); } |
ËÄ¡¢ ¹«Æ½ËøºÍ·Ç¹«Æ½ËøµÄÇø±ð
¹«Æ½ËøºÍ·Ç¹«Æ½Ëø£¬ÔÚCHL¶ÓÁÐÇÀռģʽÉ϶¼ÊÇÒ»Öµģ¬Ò²¾ÍÊÇÔÚ½øÈëacquireQueuedÕâ¸ö·½·¨Ö®ºó¶¼Ò»Ñù£¬ËüÃǵÄÇø±ðÔÚ³õ´ÎÇÀÕ¼ÉÏÓÐÇø±ð£¬Ò²¾ÍÊÇtryAcquireÉϵÄÇø±ð£¬ÏÂÃæÊÇÁ½ÕßÄÚ²¿µ÷ÓùØÏµµÄ¼òͼ£º
NonfairSync lock ¡ª> compareAndSetState | ¡ª> setExclusiveOwnerThread ¡ª> accquire | ¡ª> tryAcquire |¡ª>nonfairTryAcquire |¡ª> acquireQueued
FairSync
lock ¡ª> acquire
| ¡ª> tryAcquire
|¡ª>!hasQueuePredecessors
|¡ª>compareAndSetState
|¡ª>setExclusiveOwnerThread
|¡ª> acquireQueued |
ÕæÕýµÄÇø±ð¾ÍÊǹ«Æ½Ëø¶àÁËhasQueuePredecessorsÕâ¸ö·½·¨£¬Õâ¸ö·½·¨ÓÃÓÚÅжÏCHL¶ÓÁÐÖÐÊÇ·ñÓнڵ㣬¶ÔÓÚ¹«Æ½Ëø£¬Èç¹ûCHL¶ÓÁÐÓнڵ㣬ÔòнøÈ뾺ÕùµÄÏß³ÌÒ»¶¨ÒªÔÚCHLÉÏÅŶӣ¬¶ø·Ç¹«Æ½ËøÔòÊÇÎÞÊÓCHL¶ÓÁÐÖеĽڵ㣬ֱ½Ó½øÐоºÕùÇÀÕ¼£¬Õâ¾ÍÓпÉÄܵ¼ÖÂCHL¶ÓÁÐÉϵĽڵãÓÀÔ¶»ñÈ¡²»µ½Ëø£¬Õâ¾ÍÊǷǹ«Æ½ËøÖ®ËùÒÔ²»¹«Æ½µÄÔÒò¡£
Îå¡¢ ×ܽá
Ïß³ÌʹÓÃReentrantLock»ñÈ¡Ëø·ÖΪÁ½¸ö½×¶Î£¬µÚÒ»¸ö½×¶ÎÊdzõ´Î¾ºÕù£¬µÚ¶þ¸ö½×¶ÎÊÇ»ùÓÚCHL¶ÓÁеľºÕù¡£ÔÚ³õ´Î¾ºÕùµÄʱºòÊÇ·ñ¿¼ÂǶÓÁнڵãÖ±½ÓÇø·Ö³öÁ˹«Æ½ËøºÍ·Ç¹«Æ½Ëø¡£ÔÚ»ùÓÚCHL¶ÓÁеÄËø¾ºÕùÖУ¬ÒÀ¿¿CAS²Ù×÷±£Ö¤Ô×Ó²Ù×÷£¬ÒÀ¿¿LockSupportÀ´×öÏß³ÌµÄ¹ÒÆðºÍ»½ÐÑ£¬Ê¹ÓöÓÁÐÀ´±£Ö¤²¢·¢Ö´Ðбä³ÉÁË´®ÐÐÖ´ÐУ¬´Ó¶øÏû³ýÁ˲¢·¢Ëù´øÀ´µÄÎÊÌâ¡£×ÜÌåÀ´Ëµ£¬ReentrantLockÊÇÒ»¸ö±È½ÏÇáÁ¿¼¶µÄËø£¬¶øÇÒʹÓÃÃæÏò¶ÔÏóµÄ˼ÏëȥʵÏÖÁËËøµÄ¹¦ÄÜ£¬±ÈÔÀ´µÄsynchronized¹Ø¼ü×Ö¸ü¼ÓºÃÀí½â¡£
|