0

我是java中多线程的新手。我试图使用锁。这是我的代码示例。

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()时,它应该获得锁,其他线程应该无法获得锁。但是如输出所示。Thread-1获得锁后,Thread-2也获得锁等。这怎么可能。请告诉我我在这里缺少什么。提前致谢。

4

5 回答 5

2

原因是如果锁已经被另一个线程持有,tryLock 永远不会阻塞。

以下是有关 tryLock() 的文档

公共布尔 tryLock()

仅当调用时没有被另一个线程持有时才获取锁。

如果锁没有被另一个线程持有,则获取锁,并立即返回值为 true,将锁持有计数设置为 1。即使此锁已设置为使用公平排序策略,如果该锁可用,则调用 tryLock() 将立即获取该锁,而不管其他线程当前是否正在等待该锁。这种“闯入”行为在某些情况下可能很有用,即使它破坏了公平性。如果您想尊重此锁的公平设置,请使用几乎等效的 tryLock(0, TimeUnit.SECONDS) (它也检测中断)。

如果当前线程已经持有这个锁,那么持有计数加一并且该方法返回真。

如果锁被另一个线程持有,则此方法将立即返回值为 false。

于 2015-09-20T15:26:03.227 回答
0

ReentrantLock#tryLock()- 只有在调用时没有被另一个线程持有时才获取锁,如果成功则返回 true,否则返回 false。

如果我们看到堆栈跟踪 -

...
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
...

更清楚的是,无法获得锁的线程在尝试释放锁时引发异常。

于 2015-09-20T15:37:08.517 回答
0

尝试这样的事情以使其更清晰。

    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 .. ");
    }
于 2015-09-20T15:50:44.363 回答
0

我稍微修改了您的代码并为自己尝试了它。

我发现无论我做什么,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 https://stackoverflow.com/questions/32680954/reetrant-locks-in-java
 * @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()));
        }
    }
}
于 2015-09-20T19:21:01.733 回答
0

对 tryLock() 的调用只是返回一个布尔值,它与下一行/语句(如果有的话)是否会执行“无关”。这就是为什么应该使用 tryLock() 作为检查来执行一些想要同步的活动/代码块的原因。希望这能回答你的问题。

于 2020-01-21T21:16:21.667 回答