在线重定义过程中需要exclusive lock.

本文探讨了通过调整Oracle数据库中的DDL_LOCK_TIMEOUT参数来延长DDL操作等待时间的方法,以提高表在线重定义等操作的成功率。

执行DBMS_REDEFINITION.FINISH_REDEF_TABLE 存储过程完成表的在线重定

义。在此procedure运行过程中,原表会被以Exclusive lock mode(TM lmode=6)排他模式锁住

极为短暂的一段时间(秒级),具体这段时间的长短受到原表上数据量的影响。但有时候应用繁忙时可能不能立刻获得!

那么能不能使用一个参数让它多等待一段时间呢?

下面做个实验看看:

Microsoft Windows [版本 6.1.7601]
版权所有 (c) 2009 Microsoft Corporation。保留所有权利。

C:\Users\ibsadmin>sqlplus / as sysdba

SQL*Plus: Release 11.2.0.1.0 Production on 星期四 8月 16 17:49:47 2012

Copyright (c) 1982, 2010, Oracle.  All rights reserved.


连接到:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> show parameter ddl_lock_timeout

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
ddl_lock_timeout                     integer     0
SQL> select A.sid, b.serial#,
  2    decode(A.type,
  3        'MR', 'Media Recovery',
  4        'RT','Redo Thread',
  5        'UN','User Name',
  6        'TX', 'Transaction',
  7        'TM', 'DML',
  8        'UL', 'PL/SQL User Lock',
  9        'DX', 'Distributed Xaction',
 10       'CF', 'Control File',
 11       'IS', 'Instance State',
 12       'FS', 'File Set',
 13       'IR', 'Instance Recovery',
 14       'ST', 'Disk Space Transaction',
 15       'TS', 'Temp Segment',
 16       'IV', 'Library Cache Invalida-tion',
 17       'LS', 'Log Start or Switch',
 18       'RW', 'Row Wait',
 19       'SQ', 'Sequence Number',
 20       'TE', 'Extend Table',
 21       'TT', 'Temp Table',
 22       'Unknown') LockType,
 23   c.object_name,
 24   b.username,
 25   b.osuser,
 26   decode(a.lmode,   0, 'None',
 27               1, 'Null',
 28               2, 'Row-S',
 29               3, 'Row-X',
 30               4, 'Share',
 31               5, 'S/Row-X',
 32               6, 'Exclusive', 'Unknown') LockMode,
 33   B.MACHINE,D.SPID
 34   from v$lock a,v$session b,all_objects c,V$PROCESS D
 35   where a.sid=b.sid and a.type in ('TM','TX')
 36   and c.object_id=a.id1
 37   AND B.PADDR=D.ADDR;

未选定行

在另一个SESSION:

Microsoft Windows [版本 6.1.7601]
版权所有 (c) 2009 Microsoft Corporation。保留所有权利。

C:\Users\ibsadmin>sqlplus / as sysdba

SQL*Plus: Release 11.2.0.1.0 Production on 星期四 8月 16 17:52:55 2012

Copyright (c) 1982, 2010, Oracle.  All rights reserved.


连接到:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> create table t (cloa int);

表已创建。

SQL> insert into t values(1);

已创建 1 行。

 

SQL>

回到原来的session:
SQL> set timing on
SQL> truncate table t;
truncate table t
               *
第 1 行出现错误:
ORA-00054: 资源正忙, 但指定以 NOWAIT 方式获取资源, 或者超时失效


已用时间:  00: 00: 00.10
SQL>  select A.sid, b.serial#,
  2     decode(A.type,
  3         'MR', 'Media Recovery',
  4         'RT','Redo Thread',
  5         'UN','User Name',
  6         'TX', 'Transaction',
  7         'TM', 'DML',
  8         'UL', 'PL/SQL User Lock',
  9         'DX', 'Distributed Xaction',
 10        'CF', 'Control File',
 11        'IS', 'Instance State',
 12        'FS', 'File Set',
 13        'IR', 'Instance Recovery',
 14        'ST', 'Disk Space Transaction',
 15        'TS', 'Temp Segment',
 16        'IV', 'Library Cache Invalida-tion',
 17        'LS', 'Log Start or Switch',
 18        'RW', 'Row Wait',
 19        'SQ', 'Sequence Number',
 20        'TE', 'Extend Table',
 21        'TT', 'Temp Table',
 22        'Unknown') LockType,
 23    c.object_name,
 24    b.username,
 25    b.osuser,
 26    decode(a.lmode,   0, 'None',
 27                1, 'Null',
 28                2, 'Row-S',
 29                3, 'Row-X',
 30                4, 'Share',
 31                5, 'S/Row-X',
 32                6, 'Exclusive', 'Unknown') LockMode,
 33    B.MACHINE,D.SPID
 34    from v$lock a,v$session b,all_objects c,V$PROCESS D
 35    where a.sid=b.sid and a.type in ('TM','TX')
 36    and c.object_id=a.id1
 37    AND B.PADDR=D.ADDR;

       SID    SERIAL# LOCKTYPE                    OBJECT_NAME
---------- ---------- --------------------------- ------------------------------

USERNAME                       OSUSER                         LOCKMODE
------------------------------ ------------------------------ ---------
MACHINE
----------------------------------------------------------------
SPID
------------------------
        31       1615 DML                         T
SYS                            115-DTHVM\ibsadmin             Row-X
WORKGROUP\115-DTHVM
3748


已用时间:  00: 00: 00.18
SQL> alter session set ddl_lock_timeout = 5;

会话已更改。

已用时间:  00: 00: 00.01
SQL> truncate table t;
truncate table t
               *
第 1 行出现错误:
ORA-00054: 资源正忙, 但指定以 NOWAIT 方式获取资源, 或者超时失效


已用时间:  00: 00: 05.01

另一个SESSION提交数据:

回到原来 session执行:
SQL> truncate table t;

表被截断。

已用时间:  00: 00: 03.14
SQL>

虽然不能保证每次都成功,但完全可以增加成功的机率!

 

 

 

 

 

 


 

<think>我们正在讨论Java中的Lock接口。用户已经知道Lock接口的基本方法,现在想深入了解每个方法的内部实现逻辑。然而,Lock是一个接口,它本身没有实现,具体的实现逻辑取决于它的实现类,比如ReentrantLock。因此,我们需要以ReentrantLock为例来解释这些方法的实现,因为它是Java中最常用的Lock实现。 注意:Lock接口的方法包括: void lock(); void lockInterruptibly() throws InterruptedException; boolean tryLock(); boolean tryLock(long time, TimeUnit unit) throws InterruptedException; void unlock(); Condition newCondition(); 由于Lock接口的具体实现是由不同的锁类来完成的,我们将以ReentrantLock为例,因为它内部使用了AQS(AbstractQueuedSynchronizer)来实现。 下面我们逐一解释每个方法在ReentrantLock中的实现逻辑: 1. lock()方法: 在ReentrantLock中,lock()方法会调用内部同步器(Sync)的lock方法。Sync有两个子类:NonfairSync(非公平锁)和FairSync(公平锁)。默认是非公平锁。 非公平锁的实现逻辑: 首先尝试通过CAS操作将AQS中的state状态从0设置为1(表示获取锁),如果成功,则将当前线程设置为独占锁的拥有者。 如果CAS失败,则调用AQS的acquire(1)方法,该方法会再次尝试获取锁(tryAcquire),如果失败则将当前线程加入等待队列并挂起。 公平锁的实现逻辑: 直接调用acquire(1),在tryAcquire方法中,会先检查是否有等待队列,如果有则不会尝试获取锁(除非是重入),这样保证了按照请求锁的顺序获取锁。 2. unlock()方法: 调用Sync的release(1)方法,该方法定义在AQS中。首先会调用tryRelease方法(在Sync中实现)来释放锁(将state减1,如果state为0则完全释放),然后唤醒等待队列中的下一个线程。 3. tryLock()方法: 非阻塞尝试获取锁。在ReentrantLock中,它直接调用Sync的nonfairTryAcquire方法(非公平获取)。该方法会尝试获取锁,如果当前锁没有被任何线程持有,则通过CAS设置state为1,并设置当前线程为锁持有者;如果当前线程已经持有锁,则state加1(重入);否则返回false。 4. tryLock(long time, TimeUnit unit)方法: 带超时的尝试获取锁。该方法在AQS中实现(通过调用tryAcquireNanos)。它会先尝试非阻塞获取锁,如果失败,则进入等待队列,然后自旋等待直到超时或者被中断。在等待过程中,如果被中断则抛出InterruptedException。 5. lockInterruptibly()方法: 可中断的获取锁。同样调用AQS的acquireInterruptibly(1)方法。该方法在获取锁的过程中,如果线程被中断,会立即响应中断并抛出InterruptedException。 6. newCondition()方法: 返回一个ConditionObject对象(AQS的内部类)。ConditionObject实现了Condition接口,它内部维护了一个条件队列。当调用await()时,会将当前线程加入条件队列并释放锁,然后挂起。当调用signal()时,会将条件队列中的某个线程转移到等待队列(同步队列)中,等待获取锁。 由于具体实现涉及AQS,这里简要描述AQS的核心思想: AQS使用一个int成员变量state表示同步状态,通过内置的FIFO队列(CLH队列的变体)管理获取锁的线程。 下面我们给出ReentrantLock中部分方法的代码片段(以非公平锁为例)并解释: 注意:以下代码基于JDK 17(具体实现可能因版本而异,但核心思想不变) 1. lock()方法(非公平锁): 在ReentrantLock.NonfairSync类中: final void lock() { if (compareAndSetState(0, 1)) // 首先尝试快速获取锁 setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); // 调用AQS的acquire方法 } AQS的acquire方法: public final void acquire(int arg) { if (!tryAcquire(arg) && // 尝试获取锁,如果失败则加入队列并挂起 acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); // 在等待过程中被中断,则重新设置中断标志 } 其中tryAcquire在非公平锁中实现(nonfairTryAcquire): 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; } 2. unlock()方法: 在ReentrantLock中: public void unlock() { sync.release(1); } AQS的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; } tryRelease在ReentrantLock.Sync中: 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; } 3. tryLock()方法: public boolean tryLock() { return sync.nonfairTryAcquire(1); // 直接调用非公平的获取方式 } 4. tryLock(long timeout, TimeUnit unit)方法: public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } AQS中的tryAcquireNanos: public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); return tryAcquire(arg) || // 先尝试一次 doAcquireNanos(arg, nanosTimeout); // 如果失败,则进行带超时的自旋获取 } 5. lockInterruptibly()方法: public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } AQS的acquireInterruptibly: public final void acquireInterruptibly(int arg) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); if (!tryAcquire(arg)) doAcquireInterruptibly(arg); // 可中断的获取 } 6. newCondition()方法: public Condition newCondition() { return sync.newCondition(); } Sync中的newCondition: final ConditionObject newCondition() { return new ConditionObject(); } 以上是ReentrantLock中各个方法的核心实现逻辑。由于AQS的复杂性,这里只做了简要说明。实际上,AQS内部通过一个双向队列(CLH队列)来管理等待线程,并使用LockSupport来挂起和唤醒线程。 总结:Lock接口的方法在ReentrantLock中的实现依赖于AQS,而AQS提供了同步状态的管理、线程的排队与唤醒等底层支持。不同的锁实现(如ReentrantLock、ReentrantReadWriteLock)会基于AQS实现自己的同步语义。 注意:由于用户要求解释内部代码逻辑,我们引用了部分代码片段,并做了简要解释。更详细的实现需要阅读JDK源码。 根据用户要求,我们生成相关问题:</think>### Java `Lock`接口方法详解及内部实现逻辑 `Lock`接口在`java.util.concurrent.locks`包中定义,其核心实现依赖于**AbstractQueuedSynchronizer (AQS)**[^1]。以下是每个方法的声明、功能说明及关键实现逻辑(以`ReentrantLock`为例): --- #### 1. **`void lock()`** **功能**:阻塞式获取锁,若锁被占用则线程进入等待队列。 **内部逻辑**: ```java // ReentrantLock.NonfairSync 实现 final void lock() { if (compareAndSetState(0, 1)) // CAS 尝试直接获取锁(非公平策略) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); // 调用 AQS 的 acquire() } ``` - **AQS 的 `acquire()` 流程**: 1. 调用 `tryAcquire()` 尝试获取锁(子类实现)。 2. 若失败,将线程封装为 `Node` 加入 **CLH 队列**尾部[^1]。 3. 通过 `LockSupport.park()` 挂起线程(底层调用 Unsafe 类)。 --- #### 2. **`boolean tryLock()`** **功能**:非阻塞尝试获取锁,成功返回 `true`,失败立即返回 `false`。 **内部逻辑**: ```java // ReentrantLock.Sync 实现 final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); // 获取 AQS 的 state 值 if (c == 0) { // 锁未被占用 if (compareAndSetState(0, acquires)) { // CAS 设置 state setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { // 重入逻辑 setState(c + acquires); // 增加重入次数 return true; } return false; // 锁已被其他线程占用 } ``` - **关键点**:直接通过 **CAS 操作**修改 AQS 的 `state` 字段(0=未占用,≥1=占用次数)[^1]。 --- #### 3. **`boolean tryLock(long timeout, TimeUnit unit)`** **功能**:带超时的锁获取,支持中断。 **内部逻辑**(AQS 的 `tryAcquireNanos()`): 1. 检查中断状态,若中断则抛出 `InterruptedException`。 2. 尝试 `tryAcquire()` 获取锁,若成功返回 `true`。 3. 计算超时截止时间,循环执行: - 使用 `LockSupport.parkNanos()` 挂起指定时间。 - 若被中断或超时,取消获取锁并从队列移除节点。 --- #### 4. **`void lockInterruptibly()`** **功能**:可中断的锁获取。 **内部逻辑**(AQS 的 `acquireInterruptibly()`): ```java public final void acquireInterruptibly(int arg) { if (Thread.interrupted()) throw new InterruptedException(); if (!tryAcquire(arg)) doAcquireInterruptibly(arg); // 处理中断 } ``` - **中断响应**:在挂起过程中若线程被中断,立即抛出 `InterruptedException` 并取消锁请求。 --- #### 5. **`void unlock()`** **功能**:释放锁。 **内部逻辑**(`ReentrantLock.Sync` 实现): ```java 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); // 更新 state return free; // 返回锁是否完全释放 } ``` - **AQS 后续流程**:若锁完全释放,唤醒队列中下一个等待线程。 --- #### 6. **`Condition newCondition()`** **功能**:创建与锁绑定的 `Condition` 对象。 **内部逻辑**: ```java // ReentrantLock 实现 public Condition newCondition() { return sync.newCondition(); // 返回 AQS.ConditionObject } ``` - **ConditionObject 原理**: - 内部维护一个**条件队列**(单向链表)。 - `await()`:释放锁,将线程加入条件队列并挂起。 - `signal()`:将条件队列的头节点转移到 **AQS 主队列**等待获取锁[^1]。 --- ### 关键实现机制总结 | **组件** | **作用** | |-------------------|--------------------------------------------------------------------------| | **AQS 的 state** | 锁状态(0=未占用,≥1=重入次数) | | **CLH 队列** | 双向链表实现的等待队列,存储阻塞线程 | | **CAS 操作** | 通过 `Unsafe.compareAndSwapInt` 原子更新 `state`,避免竞态条件 | | **LockSupport** | 底层线程挂起/唤醒工具(`park()`/`unpark()`) | > **设计哲学**: > - **锁与同步器分离**:`Lock` 定义用户接口,AQS 提供同步框架(模板方法模式)。 > - **非公平锁优先**:默认策略减少线程切换开销(可通过 `ReentrantLock(true)` 启用公平锁)。 --- ### 相关问题 1. AQS 的 **CLH 队列**如何避免线程饥饿问题? 2. 为什么 `Condition.await()` 必须在持有锁时调用? 3. **非公平锁**在哪些场景下性能优于公平锁?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值