Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/371.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
可以显式使用Java内部锁吗?_Java_Locking_Synchronized_Monitor_Locks - Fatal编程技术网

可以显式使用Java内部锁吗?

可以显式使用Java内部锁吗?,java,locking,synchronized,monitor,locks,Java,Locking,Synchronized,Monitor,Locks,在Java中,假设您有一个数组: Object[] objs = {o1, o2, ... , oN}; 以及一个关键部分: { critical(); } 您希望在保持objs中每个元素的内在锁的同时执行critical部分 我可以想出一种方法来做到这一点,它涉及到对递归的可恶滥用: void syncArray(int i) { if (i >= 0) { synchronized(objs[i]) { syncArray(i - 1); }

在Java中,假设您有一个数组:

Object[] objs = {o1, o2, ... , oN};
以及一个关键部分:

{
 critical();
}
您希望在保持objs中每个元素的内在锁的同时执行critical部分

我可以想出一种方法来做到这一点,它涉及到对递归的可恶滥用:

void syncArray(int i) {
  if (i >= 0) {
    synchronized(objs[i]) {
       syncArray(i - 1);
    }
  } else {
    critical();
  }
}

syncArray(objs.length - 1);
除了丑陋之外,这还需要O(N)个堆栈帧,这可能不是很好。有更好的办法吗?我真正想要的是一种在不使用synchronized关键字的情况下获取和释放内部锁的方法。如果您使用非阻塞方式尝试获取内在锁,则可获得额外点数


注意:我不是问这是否是一个好主意(不是),只是问它是否可能。现实世界中的答案显然只是使用显式锁,并对尝试同时获取N个对象的锁的智慧进行一些自我反省。

这在普通Java代码中是不可能的,但可以在字节码级别上完成

然而,这样做并不值得,因为它不能解决递归方法的问题,堆栈消耗,这似乎是您唯一关心的问题

中的示例程序详细阐述了这一点,演示了在循环中获取对象监视器的字节码在可用堆栈空间和可以进行的监视器获取的最大数量之间具有直接关系

换句话说,即使是在循环中获取对象监视器的手工字节码也有O(n)堆栈消耗,对于较大的数组,可能会以与递归方法相同的方式失败

链接答案的示例代码在一个循环中获取同一对象的监视器,但即使没有得到优化,也没有理由假设获取不同对象的监视器可以获得更少的堆栈空间

关于您的“额外问题”,对于非阻塞“try‑monitorenter”,没有字节码操作。有些版本的
sun.misc.Unsafe
有一个
tryMonitorEnter
方法,但这超出了任何标准

关于结构化锁定要求,这没有问题。它只要求在方法退出时,该方法不能持有它在进入时尚未持有的任何内在锁。所以,如果您的方法获取一个循环中的所有监控器,执行临界部分,并在一个循环中释放相同的监控器,那么它在形式上是正确的。这是假设数组在这段时间内从未被修改过

但是如前所述,编写这样的字节码并没有什么好处,因为JVM不会在运行时优化这样不常见的代码,而且每次获取都会消耗堆栈空间



当然,有提到的
sun.misc.Unsafe
,但是使用它的代码不算是“普通Java代码”,甚至比讨论中的手工字节码更难移植。

i>=4
时,你大概可以通过2或4个“展开”并使用4个嵌套的
同步(objs[i-0..3])
块来获取4个锁。如果递归不只是变成一个循环的话,这可能会让JIT变成不那么糟糕的asm。使用
objs
作为锁对你来说不是一个选项吗?所以回答了我自己的问题:我要看看是否可以将monitorenter和monitorexit字节码指令包装在它们自己的函数中,这样就可以不用配对就可以调用它们。事实证明,这段代码可能会被JVM实现破坏,因为规范说,强制执行函数退出时对象的monitorenter和monitorexit调用数必须相同是“允许的,但不是必需的”。这意味着我在这个问题上的要求是不可能的!虽然这听起来好像你不能把这些指令放在它们自己的函数中,但是你能在循环中构造一个函数来发出它们吗?所以你在考虑直接使用Java字节码是否可行,不管你是否能编写Java源代码来编译成这样的字节码?(或通过库创建)。