有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java中的多线程Reetrant锁

我不熟悉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()时,它应该获得锁,而其他线程不应该能够获得锁。但正如输出所示。线程1获得锁后,线程2也获得锁,依此类推。这怎么可能呢。请告诉我这里缺少什么。 提前谢谢


共 (5) 个答案

  1. # 1 楼答案

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

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

  2. # 2 楼答案

    调用tryLock()时,只返回一个布尔值,它在下一行/语句(如果有)是否执行时具有无方向性“。 这就是为什么tryLock()应该被用作检查执行某些活动/代码块的原因,这些活动/代码块需要同步。希望这能回答你的问题

  3. # 3 楼答案

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

    下面是关于tryLock()的文档

    public boolean tryLock()

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

    如果锁未被另一个线程持有,则获取锁,并立即返回值true,将锁持有计数设置为1。即使将该锁设置为使用公平排序策略,调用tryLock()也会立即获取该锁(如果该锁可用),无论当前是否有其他线程正在等待该锁。这种“讨价还价”行为在某些情况下是有用的,即使它破坏了公平性。如果您希望遵守此锁的公平性设置,则使用几乎相等的tryLock(0,TimeUnit.SECONDS)(它还检测中断)

    如果当前线程已经持有该锁,那么持有计数将增加1,并且该方法返回true

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

  4. # 4 楼答案

    我对你的代码做了一些修改,并亲自尝试了一下

    我找到了那个可重入锁。不管我做了什么,tryLock都会抛出一个非法的MonitorStateException。我认为这不合适

    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()));
            }
        }
    }
    
  5. # 5 楼答案

    试着做些这样的事情,让它更清楚

        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 .. ");
        }