gpt4 book ai didi

java - ReentrantLock 允许线程多次锁定某个资源

转载 作者:太空宇宙 更新时间:2023-11-04 09:56:32 28 4
gpt4 key购买 nike

ReentrantLock 允许线程多次锁定某个资源,

这在执行/效率/功能方面有何好处?

请参阅此链接,https://www.geeksforgeeks.org/reentrant-lock-java/

我没有明白使用内锁的意义,因为一旦任何一个线程获得了外锁,其他线程就无法进入外锁之后的部分(直到该线程持有时间锁),而且外锁之后的部分一次只能由一个线程执行,那么内锁有什么意义,意味着多次进入锁有什么意义?

代码:

import java.text.SimpleDateFormat; 
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;

class worker implements Runnable
{
String name;
ReentrantLock re;
public worker(ReentrantLock rl, String n)
{
re = rl;
name = n;
}
public void run()
{
boolean done = false;
while (!done)
{
//Getting Outer Lock
boolean ans = re.tryLock();

// Returns True if lock is free
if(ans)
{
try
{
Date d = new Date();
SimpleDateFormat ft = new SimpleDateFormat("hh:mm:ss");
System.out.println("task name - "+ name
+ " outer lock acquired at "
+ ft.format(d)
+ " Doing outer work");
Thread.sleep(1500);

// Getting Inner Lock
re.lock();
try
{
d = new Date();
ft = new SimpleDateFormat("hh:mm:ss");
System.out.println("task name - "+ name
+ " inner lock acquired at "
+ ft.format(d)
+ " Doing inner work");
System.out.println("Lock Hold Count - "+ re.getHoldCount());
Thread.sleep(1500);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
finally
{
//Inner lock release
System.out.println("task name - " + name +
" releasing inner lock");

re.unlock();
}
System.out.println("Lock Hold Count - " + re.getHoldCount());
System.out.println("task name - " + name + " work done");

done = true;
}
catch(InterruptedException e)
{
e.printStackTrace();
}
finally
{
//Outer lock release
System.out.println("task name - " + name +
" releasing outer lock");

re.unlock();
System.out.println("Lock Hold Count - " +
re.getHoldCount());
}
}
else
{
System.out.println("task name - " + name +
" waiting for lock");
try
{
Thread.sleep(1000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}
}

public class test
{
static final int MAX_T = 2;
public static void main(String[] args)
{
ReentrantLock rel = new ReentrantLock();
ExecutorService pool = Executors.newFixedThreadPool(MAX_T);
Runnable w1 = new worker(rel, "Job1");
Runnable w2 = new worker(rel, "Job2");
Runnable w3 = new worker(rel, "Job3");
Runnable w4 = new worker(rel, "Job4");
pool.execute(w1);
pool.execute(w2);
pool.execute(w3);
pool.execute(w4);
pool.shutdown();
}
}

最佳答案

我认为解释它是如何工作的是多余的,我们应该只使用 lock() 或 tryLock() 方法之一:

如果你的线程有多个任务要执行,其中一些任务与锁无关,那么你应该使用tryLock()。如果您的线程需要执行的所有任务都依赖于锁,那么您应该使用lock()。

也就是说,当线程已经或可以获取独立于锁获取的额外工作时,您应该使用 tryLock() 而不是 lock()。

-----可选:

假设您有四个任务(1 到 3),它们由具有两个工作线程 A 和 B 的线程池执行。任务 1 和 2 共享一个资源,该资源必须一次由一个线程访问,以防止损坏。

现在如果你不试用就直接锁定,你可能会遇到以下情况:

  1. 线程 A 启动任务 1;

  2. 线程A获取资源锁;

  3. 线程 B 启动任务 2;
  4. 线程 B 尝试获取锁,但被阻塞( hibernate );
  5. 线程A完成任务1,释放锁;
  6. 线程B醒来,但线程A还没有切换;
  7. 线程 A 启动任务 3;
  8. 线程B再次尝试获取锁;
  9. 线程B获取锁并完成任务2;
  10. 线程 A 完成任务 3。

注意lock()会挂起一个线程直到锁被释放,所以线程B在线程A释放锁之前是完全无用的。线程 B 可以启动任务 3,而不是等待锁,并同时完成它。

使用 try-lock 的算法可以像这样执行:

  1. 线程 A 启动任务 1;
  2. 线程A测试并获取锁;
  3. 线程 B 启动任务 2;
  4. 线程 B 测试锁,跳过任务 2;
  5. 线程 B 启动任务 3;
  6. 线程A完成任务1,释放锁;
  7. 线程 A 启动任务 2;
  8. 线程 B 完成任务 3;
  9. 没有更多任务,因此线程 B hibernate ;
  10. 线程 A 完成任务 2,释放锁。

请注意,tryLock() 不会挂起调用线程,因此可以跳过阻塞任务,而线程 B 执行非阻塞任务。如果任务 1 和 2 很长,并且还有其他几个短的非阻塞任务,那么它们都可以在任务 1 完成或任务 2 开始之前完成。

当然,实现线程池和任务管理比普通锁定要复杂一些:任务可能必须挂起并返回到池中;当任何锁被释放时, hibernate 的空闲线程应该被唤醒。

如果您有许多非阻塞任务(或者至少不在同一个锁上阻塞)以及一些阻塞任务,那么麻烦是值得的,但如果所有任务都在同一资源上阻塞,那么一开始就不值得实现多线程。

关于java - ReentrantLock 允许线程多次锁定某个资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54087766/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com