当前位置: 首页 > 知识库问答 >
问题:

允许线程多次进入资源上的锁

尉迟国发
2023-03-14

Reentry antLock允许线程多次进入资源的锁,

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

请参考此链接,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(); 
  } 
}

共有2个答案

秦景同
2023-03-14

假设在一个类中有两个方法m1和m2,它们都是同步的,m2正在调用m1。在这种情况下,如果线程a已经锁定了m1,并且不允许再次锁定,那么thresad将继续等待调用m2(因为它已经锁定了)

更多详情:

https://stackoverflow.com/questions/18596080/java-concurrent-reentrantlock-why-we-want-to-acquire-the-same-lock-multiple-ti

昝成弘
2023-03-14

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

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

也就是说,当线程拥有或可以获得独立于锁获取的额外工作时,应该使用tryLock()over lock()。

-----可选:

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

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

>

  • 线程A启动任务1;

    线程A获取资源锁;

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

    使用try lock的算法可以执行如下操作:

    1. 线程A启动任务1

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

    当然,实现线程池和任务管理比简单的锁定要复杂一点:任务可能必须暂停并返回到池中;并且在释放任何锁时应该唤醒Hibernate的空闲线程。

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

  •  类似资料:
    • 背景知识 所有网络交流都是在主浏览器进程处理的。这样浏览器进程不仅可以控制每个渲染器的网络访问,还可以在进程间维持session状态一致性,像cookie和缓存数据。另一个重要的原因是,作为一个HTTP/1.1的用户代理,浏览器整体上在每个host上不能打开太多连接。 概述 我们的多进程应用程序可以从三个层面来看。在最底层是WebKit库,用来渲染页面。在它上面是渲染器进程(简单地,每个标签页对应

    • 主要内容:系统资源使用调用进程需要一定的资源,如CPU和内存来执行任务。 现在我们将查看相关的命令和系统调用来了解资源利用和监视的信息。 此外,资源上的每个过程在默认情况下都有一定的限制,如果需要,可以增加限制以适应应用需求。 以下是使用命令的基本系统或过程资源信息 - top命令 命令不断显示系统资源的使用情况。 如果任何进程使系统处于某种挂起状态(消耗更多的CPU或内存),则可能会记录进程信息并采取相应的措施(例如,杀

    • 进程文件 在Linux中“一切皆文件”,进程的一切运行信息(占用CPU、内存等)都可以在文件系统找到,例如看一下PID为1的进程信息。 root@87096bf68cb2:/go/src# ls /proc/1/ attr cmdline cwd fdinfo loginuid mounts numa_maps pagemap

    • 我犯了这个错误 无法加载XMLHttpRequesthttp://domain.com/canvas/include/rs-plugin/js/extensions/revolution.extension.video.min.js.飞行前响应中的访问控制允许标头不允许请求标头字段X-Requested-With。 我的php页面顶部有这两行代码,用于加载这个js文件。 但是问题依然存在,我该怎么

    • 我试着把数据从React.jslocalhostinsert.php文件。当我提交的形式从reactjs它给我错误的控制台错误是: 访问位于“”的XMLHttpRequesthttp://localhost/reactphpdemo/connect.php“起源”http://localhost:3000'已被CORS策略阻止:对飞行前请求的响应未通过访问控制检查:请求的资源上不存在'access

    • 当我试图从另一个域访问rest服务时,我得到了以下错误 无法加载对飞行前请求的响应没有通过访问控制检查:请求的资源上没有“访问-控制-允许-起源”标头。因此,不允许访问源'http://localhost:8080'。 我将服务器端配置为响应跨域调用,这可以用于GET调用,但POST调用会产生错误 谢谢