假设我有以下代码片段,其中两个线程使用两个关键部分(同步语句)访问同一方法。这些同步语句中的每一个都被赋予一个不同的锁对象。代码如下:
public class MyWorker {
private Random random = new Random();
private Object lock1 = new Object();
private Object lock2 = new Object();
private List<Integer> list1 = new ArrayList<>();
private List<Integer> list2 = new ArrayList<>();
private void stageOne() {
synchronized (lock1) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
list1.add(random.nextInt(100));
}
}
private void stageTwo() {
synchronized (lock2) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
list2.add(random.nextInt(100));
}
}
private void process() {
for (int i=0; i<1000; i++) {
stageOne();
stageTwo();
}
}
void main() {
Thread t1 = new Thread(this::process);
Thread t2 = new Thread(this::process);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
我的问题不是关于此代码中的错误,也不是有关如何以Java立场执行的。此代码可以正常工作。我只是将其作为参考代码,以便回答的人有一个特定的场景可以参考。我想知道JVM如何在内部创建与此实例相关联的监视对象,以及如何根据该场景在内部进行对象锁定使用OpenJDK实现。 我希望得到一个简短的解释。
我对这个话题进行了几天的研究,找不到深入的解释。这些是我经历过的一些发现:
这些方法中最基本的是同步,它是使用监视器实现的。 Java中的每个对象都与一个监视器关联,线程可以锁定或解锁监视器。一次只能有一个线程在监视器上保持锁。尝试锁定该监视器的所有其他线程将被阻止,直到它们可以在该监视器上获得锁定为止。线程t可以多次锁定特定的监视器。每次解锁都会逆转一次锁定操作的效果。
在Java虚拟机中,每个对象和类在逻辑上都与监视器关联。对于对象,关联的监视器将保护对象的实例变量。对于类,监视器将保护类的类变量。如果对象没有实例变量,或者类没有类变量,则关联的监视器将不保护数据。
为了实现监视器的互斥功能,Java虚拟机将锁(有时称为互斥锁)与每个对象和类关联。锁就像特权,一次只能有一个线程“拥有”。线程无需获取锁即可访问实例或类变量。但是,如果某个线程确实获得了锁,则只有拥有该锁的线程将其释放后,其他线程才能在同一数据上获得锁。 (“锁定对象”是获取与该对象关联的监视器。)
我知道在指令集级别如何使用 monitorenter 和 monitorexit 操作码来管理同步语句。但是我试图通过JVM源代码级别更深入地了解。但是,由于我在源代码中有很多不足之处,因此我仍在努力将OpenJDK源代码与通过上述链接找到的高级解释进行映射。
任何熟悉OpenJDK源代码的人都能为使用OpenJDK源代码的上述代码段的以下问题提供解释吗?我认为ObjectMonitor,BasicLock,Synchronizer类与该解释更为相关。
MyWorker
对象实例还是Object lock1
或两者兼而有之?因为JSL和Bill Vennams的解释描绘了每个对象都与一个监视器相关联。MyWorker
对象实例,如何为MyWorker
对象实例创建监视器? Object lock1
创建锁对象
我们通过答案 0 :(得分:5)
为哪个对象实例创建监视对象?
每个 Java对象也是一个 monitor对象,包括反射对象,因此您的代码至少具有以下内容:
INSERT INTO table
(a,
b)
VALUES (X,
Y)
ON DUPLICATE KEY UPDATE c = CASE
WHEN c IS NULL
THEN Y
ELSE
c
END,
d = CASE
WHEN d IS NULL
AND c IS NOT NULL
THEN Y
ELSE
d
END,
e = CASE
WHEN e IS NULL
AND d IS NOT NULL
THEN Y
ELSE
e
END,
f = CASE
WHEN f IS NULL
AND e IS NOT NULL
THEN Y
ELSE
f
END,
g = CASE
WHEN g IS NULL
AND f IS NOT NULL
THEN Y
ELSE
g
END;
的类对象var jObj= JObject.Parse(jsonstring);
var result = jObj.SelectToken("whitelist").Children().OfType<JProperty>()
.ToDictionary(p => p.Name, p=> new
{
Created = (DateTime)p.First()["create date"],
Name = (string)p.First()["name"]
});
的类对象__global__ void transpose_tiled_padded(float *A, float *B, int n)
{
int i_in = blockDim.x*blockIdx.x + threadIdx.x;
int j_in = blockDim.y*blockIdx.y + threadIdx.y;
int i_out = blockDim.x*blockIdx.y + threadIdx.x;
int j_out = blockDim.y*blockIdx.x + threadIdx.y;
extern __shared__ float tile[];
// coalesced read of A rows to (padded) shared tile column (transpose)
tile[threadIdx.y + threadIdx.x*(blockDim.y+1)] = A[i_in + j_in*n];
__syncthreads();
// coalesced write from (padded) shared tile column to B rows
B[i_out + j_out*n] = tile[threadIdx.x + threadIdx.y*(blockDim.x+1)];
}
的类对象MyWorker
的类对象Random
的类对象Object
的类对象List
实例已分配给字段Integer
ArrayList
实例已分配给字段Random
random
实例已分配给字段Object
lock1
实例已分配给字段Object
lock2
实例已分配给字段ArrayList
list1
实例已分配给局部变量ArrayList
list2
实例已分配给局部变量Thread
t1
时通过自动装箱创建的每个Thread
实例是MyWorker对象实例或对象lock1还是两者都使用?
两者
如果用于MyWorker对象实例,如何为MyWorker对象实例创建监视器?
我们如何为引用对象Object lock1创建锁对象
监视器实际上是如何由线程的锁定对象锁定的?
取决于JVM内部。没有唯一的答案,“彻底的解释”超出了本网站的范围。