java 中的可重入锁
Reetrant locks in java
我是 java 的多线程新手。我正在尝试使用 locks.Here 是我的代码示例。
package com;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class UsingLocks {
Lock lock = new ReentrantLock();
public static void main(String[] args) {
// TODO Auto-generated method stub
UsingLocks job = new UsingLocks();
Thread [] threads= new Thread[5];
for(int i=0;i<5;i++){
threads[i]= new Thread(new LockTask(job));
}
for(int i=0;i<5;i++){
threads[i].start();
}
}
public void lockingJob() {
System.out.println("Thread "+Thread.currentThread().getName()+" trying to Acquire lock");
try {
lock.tryLock();
//lock.lock(); //When I use this, code works fine
int time=new Random().nextInt(10)+3;
System.out.println("Thread "+Thread.currentThread().getName()+" Acquired lock for "+time+" seconds.");
TimeUnit.SECONDS.sleep(time);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Now releasing lock "+Thread.currentThread().getName());
lock.unlock();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("After Unlock "+Thread.currentThread().getName());
}
}
class LockTask implements Runnable{
UsingLocks job;
public LockTask(UsingLocks job) {
// TODO Auto-generated constructor stub
this.job=job;
}
@Override
public void run() {
// TODO Auto-generated method stub
job.lockingJob();
}
}
以下是我使用 tryLock() 时的输出
Thread Thread-1 trying to Acquire lock
Thread Thread-0 trying to Acquire lock
Thread Thread-2 trying to Acquire lock
Thread Thread-1 Acquired lock for 12 seconds.
Thread Thread-2 Acquired lock for 3 seconds.
Thread Thread-0 Acquired lock for 8 seconds.
Thread Thread-3 trying to Acquire lock
Thread Thread-3 Acquired lock for 9 seconds.
Thread Thread-4 trying to Acquire lock
Thread Thread-4 Acquired lock for 6 seconds.
Now releasing lock Thread-2
Exception in thread "Thread-2" java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:155)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1260)
at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:460)
at com.UsingLocks.lockingJob(UsingLocks.java:37)
at com.LockTask.run(UsingLocks.java:66)
at java.lang.Thread.run(Thread.java:745)
Now releasing lock Thread-4
Exception in thread "Thread-4" java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:155)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1260)
at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:460)
at com.UsingLocks.lockingJob(UsingLocks.java:37)
at com.LockTask.run(UsingLocks.java:66)
at java.lang.Thread.run(Thread.java:745)
现在,根据我的理解,当第一个线程执行 tryLock() 时,它应该获取锁,其他线程应该无法获得 lock.But,如 output.After 线程中所示-1获得锁,Thread-2也获得锁等等。这怎么可能。请告诉我我在这里缺少什么。
提前致谢。
原因是如果锁已经被另一个线程持有,tryLock 永远不会阻塞。
下面是关于 tryLock() 的文档
public boolean tryLock()
只有在调用时没有被另一个线程持有时才获取锁。
如果锁未被另一个线程持有,则获取锁,并且 return 立即使用值 true,将锁持有计数设置为 1。即使此锁已设置为使用公平排序策略,调用 tryLock() 也会立即获取锁(如果可用),无论其他线程当前是否正在等待锁。这种 "barging" 行为在某些情况下可能很有用,即使它破坏了公平性。如果您想遵守此锁的公平性设置,请使用几乎等效的 tryLock(0, TimeUnit.SECONDS)(它还检测中断)。
如果当前线程已经持有此锁,则持有计数递增 1,并且方法 returns 为真。
如果锁被另一个线程持有,则此方法将 return 立即返回值 false。
ReentrantLock#tryLock()
- 仅当调用时锁未被另一个线程持有时才获取锁 & returns 如果成功则为真,否则为假。
如果我们看到堆栈跟踪 -
...
Now releasing lock Thread-2
Exception in thread "Thread-2" java.lang.IllegalMonitorStateException
...
Now releasing lock Thread-4
Exception in thread "Thread-4" java.lang.IllegalMonitorStateException
...
更清楚的是,无法获得锁的线程在尝试释放锁时引发异常。
尝试这样的事情,让它更清楚。
System.out.println("Thread "+ Thread.currentThread().getName() + " trying to Acquire lock");
if (lock.tryLock()) {
try {
System.out.println("Lock acquired .. ");
int time=new Random().nextInt(10)+3;
System.out.println("Thread " + Thread.currentThread().getName() + " Acquired lock for " + time + " seconds.");
TimeUnit.SECONDS.sleep(time);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
System.out.println("Now releasing lock "+Thread.currentThread().getName());
lock.unlock();
}
} else {
System.out.println("Thread "+ Thread.currentThread().getName()+ " Failed to acquire lock .. ");
}
我稍微修改了你的代码并亲自试了一下。
我发现无论我做什么,ReentrantLock.tryLock 都会抛出 IllegalMonitorStateException。我觉得不合适。
package concurrency;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* LockableTask is a nice demonstration
* @author Michael
* @link
* @since 9/20/2015 11:25 AM
*/
public class LockableTask implements Runnable {
private static final int DEFAULT_WAIT = 100;
private static final int DEFAULT_TIMEOUT = 1000;
private static final int DEFAULT_THREADS = 5;
private ReentrantLock lock;
private int waitPeriod;
private int timeoutPeriod;
private boolean halfHeartedLockRequest;
public static void main(String[] args) {
long begTime = System.currentTimeMillis();
System.out.println("Start reentrant lock test");
try {
LockableTask lockableTask = new LockableTask(true, false);
int numThreads = (args.length > 0) ? Integer.parseInt(args[0]) : DEFAULT_THREADS;
List<Thread> threads = new ArrayList<>(numThreads);
for (int i = 0; i < numThreads; ++i) {
threads.add(new Thread(lockableTask));
}
for (Thread thread : threads) {
thread.start();
}
} finally {
long endTime = System.currentTimeMillis();
System.out.println(String.format("Complete reentrant lock test in %d milliseconds", (endTime-begTime)));
}
}
public LockableTask() {
this(false, false, DEFAULT_WAIT, DEFAULT_TIMEOUT);
}
public LockableTask(boolean halfHeartedLockRequest, boolean fair) {
this(halfHeartedLockRequest, fair, DEFAULT_WAIT, DEFAULT_TIMEOUT);
}
public LockableTask(boolean halfHeartedLockRequest, boolean fair, int waitPeriod, int timeoutPeriod) {
this.halfHeartedLockRequest = halfHeartedLockRequest;
this.lock = new ReentrantLock(fair);
this.waitPeriod = (waitPeriod > 0) ? waitPeriod : DEFAULT_WAIT;
this.timeoutPeriod = (timeoutPeriod > 0) ? timeoutPeriod : DEFAULT_TIMEOUT;
}
@Override
public void run() {
System.out.println(String.format("Thread '%s' requests lock ", Thread.currentThread().getName()));
if (this.halfHeartedLockRequest) {
this.lock.tryLock();
} else {
this.lock.lock();
}
try {
System.out.println(String.format("Thread '%s' acquires lock for %d ", Thread.currentThread().getName(), this.waitPeriod));
TimeUnit.MILLISECONDS.sleep(this.waitPeriod);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
this.lock.unlock();
System.out.println(String.format("Thread '%s' releases lock ", Thread.currentThread().getName()));
}
}
}
对 tryLock() 的调用,只是 returns 一个布尔值,它有 "no bearing" 是否 下一个line/statement,如果有的话,会不会执行。
这就是为什么 tryLock() 应该用作检查来执行一些 activities/block 代码的原因,其中一个想要同步。希望这能回答您的问题。
我是 java 的多线程新手。我正在尝试使用 locks.Here 是我的代码示例。
package com;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class UsingLocks {
Lock lock = new ReentrantLock();
public static void main(String[] args) {
// TODO Auto-generated method stub
UsingLocks job = new UsingLocks();
Thread [] threads= new Thread[5];
for(int i=0;i<5;i++){
threads[i]= new Thread(new LockTask(job));
}
for(int i=0;i<5;i++){
threads[i].start();
}
}
public void lockingJob() {
System.out.println("Thread "+Thread.currentThread().getName()+" trying to Acquire lock");
try {
lock.tryLock();
//lock.lock(); //When I use this, code works fine
int time=new Random().nextInt(10)+3;
System.out.println("Thread "+Thread.currentThread().getName()+" Acquired lock for "+time+" seconds.");
TimeUnit.SECONDS.sleep(time);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Now releasing lock "+Thread.currentThread().getName());
lock.unlock();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("After Unlock "+Thread.currentThread().getName());
}
}
class LockTask implements Runnable{
UsingLocks job;
public LockTask(UsingLocks job) {
// TODO Auto-generated constructor stub
this.job=job;
}
@Override
public void run() {
// TODO Auto-generated method stub
job.lockingJob();
}
}
以下是我使用 tryLock() 时的输出
Thread Thread-1 trying to Acquire lock
Thread Thread-0 trying to Acquire lock
Thread Thread-2 trying to Acquire lock
Thread Thread-1 Acquired lock for 12 seconds.
Thread Thread-2 Acquired lock for 3 seconds.
Thread Thread-0 Acquired lock for 8 seconds.
Thread Thread-3 trying to Acquire lock
Thread Thread-3 Acquired lock for 9 seconds.
Thread Thread-4 trying to Acquire lock
Thread Thread-4 Acquired lock for 6 seconds.
Now releasing lock Thread-2
Exception in thread "Thread-2" java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:155)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1260)
at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:460)
at com.UsingLocks.lockingJob(UsingLocks.java:37)
at com.LockTask.run(UsingLocks.java:66)
at java.lang.Thread.run(Thread.java:745)
Now releasing lock Thread-4
Exception in thread "Thread-4" java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:155)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1260)
at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:460)
at com.UsingLocks.lockingJob(UsingLocks.java:37)
at com.LockTask.run(UsingLocks.java:66)
at java.lang.Thread.run(Thread.java:745)
现在,根据我的理解,当第一个线程执行 tryLock() 时,它应该获取锁,其他线程应该无法获得 lock.But,如 output.After 线程中所示-1获得锁,Thread-2也获得锁等等。这怎么可能。请告诉我我在这里缺少什么。 提前致谢。
原因是如果锁已经被另一个线程持有,tryLock 永远不会阻塞。
下面是关于 tryLock() 的文档
public boolean tryLock()
只有在调用时没有被另一个线程持有时才获取锁。
如果锁未被另一个线程持有,则获取锁,并且 return 立即使用值 true,将锁持有计数设置为 1。即使此锁已设置为使用公平排序策略,调用 tryLock() 也会立即获取锁(如果可用),无论其他线程当前是否正在等待锁。这种 "barging" 行为在某些情况下可能很有用,即使它破坏了公平性。如果您想遵守此锁的公平性设置,请使用几乎等效的 tryLock(0, TimeUnit.SECONDS)(它还检测中断)。
如果当前线程已经持有此锁,则持有计数递增 1,并且方法 returns 为真。
如果锁被另一个线程持有,则此方法将 return 立即返回值 false。
ReentrantLock#tryLock()
- 仅当调用时锁未被另一个线程持有时才获取锁 & returns 如果成功则为真,否则为假。
如果我们看到堆栈跟踪 -
...
Now releasing lock Thread-2
Exception in thread "Thread-2" java.lang.IllegalMonitorStateException
...
Now releasing lock Thread-4
Exception in thread "Thread-4" java.lang.IllegalMonitorStateException
...
更清楚的是,无法获得锁的线程在尝试释放锁时引发异常。
尝试这样的事情,让它更清楚。
System.out.println("Thread "+ Thread.currentThread().getName() + " trying to Acquire lock");
if (lock.tryLock()) {
try {
System.out.println("Lock acquired .. ");
int time=new Random().nextInt(10)+3;
System.out.println("Thread " + Thread.currentThread().getName() + " Acquired lock for " + time + " seconds.");
TimeUnit.SECONDS.sleep(time);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
System.out.println("Now releasing lock "+Thread.currentThread().getName());
lock.unlock();
}
} else {
System.out.println("Thread "+ Thread.currentThread().getName()+ " Failed to acquire lock .. ");
}
我稍微修改了你的代码并亲自试了一下。
我发现无论我做什么,ReentrantLock.tryLock 都会抛出 IllegalMonitorStateException。我觉得不合适。
package concurrency;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* LockableTask is a nice demonstration
* @author Michael
* @link
* @since 9/20/2015 11:25 AM
*/
public class LockableTask implements Runnable {
private static final int DEFAULT_WAIT = 100;
private static final int DEFAULT_TIMEOUT = 1000;
private static final int DEFAULT_THREADS = 5;
private ReentrantLock lock;
private int waitPeriod;
private int timeoutPeriod;
private boolean halfHeartedLockRequest;
public static void main(String[] args) {
long begTime = System.currentTimeMillis();
System.out.println("Start reentrant lock test");
try {
LockableTask lockableTask = new LockableTask(true, false);
int numThreads = (args.length > 0) ? Integer.parseInt(args[0]) : DEFAULT_THREADS;
List<Thread> threads = new ArrayList<>(numThreads);
for (int i = 0; i < numThreads; ++i) {
threads.add(new Thread(lockableTask));
}
for (Thread thread : threads) {
thread.start();
}
} finally {
long endTime = System.currentTimeMillis();
System.out.println(String.format("Complete reentrant lock test in %d milliseconds", (endTime-begTime)));
}
}
public LockableTask() {
this(false, false, DEFAULT_WAIT, DEFAULT_TIMEOUT);
}
public LockableTask(boolean halfHeartedLockRequest, boolean fair) {
this(halfHeartedLockRequest, fair, DEFAULT_WAIT, DEFAULT_TIMEOUT);
}
public LockableTask(boolean halfHeartedLockRequest, boolean fair, int waitPeriod, int timeoutPeriod) {
this.halfHeartedLockRequest = halfHeartedLockRequest;
this.lock = new ReentrantLock(fair);
this.waitPeriod = (waitPeriod > 0) ? waitPeriod : DEFAULT_WAIT;
this.timeoutPeriod = (timeoutPeriod > 0) ? timeoutPeriod : DEFAULT_TIMEOUT;
}
@Override
public void run() {
System.out.println(String.format("Thread '%s' requests lock ", Thread.currentThread().getName()));
if (this.halfHeartedLockRequest) {
this.lock.tryLock();
} else {
this.lock.lock();
}
try {
System.out.println(String.format("Thread '%s' acquires lock for %d ", Thread.currentThread().getName(), this.waitPeriod));
TimeUnit.MILLISECONDS.sleep(this.waitPeriod);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
this.lock.unlock();
System.out.println(String.format("Thread '%s' releases lock ", Thread.currentThread().getName()));
}
}
}
对 tryLock() 的调用,只是 returns 一个布尔值,它有 "no bearing" 是否 下一个line/statement,如果有的话,会不会执行。 这就是为什么 tryLock() 应该用作检查来执行一些 activities/block 代码的原因,其中一个想要同步。希望这能回答您的问题。