1. 使用 t.s
加锁
javaCopy codeprivate void a(T t) {
synchronized (t.s) { // 使用 t.s 作为锁对象
System.out.println(t.s);
// 模拟一些操作,表示持有锁的时间
try {
Thread.sleep(1000); // 暂停线程 1 秒,模拟长时间操作
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
粒度
- 粒度:细粒度
- 特性:使用
t.s
作为锁对象,允许同一类的不同实例之间的并发访问。
优缺点
- 优点:
- 可以在多个线程中同时访问不同的
T
实例,只要它们的s
字段不同,这样可以提高并发性。
- 可以在多个线程中同时访问不同的
- 缺点:
- 如果多个
T
实例的s
字段指向同一个字符串(例如,"Hello"
),则会发生锁竞争,导致某些线程被阻塞。
- 如果多个
2. 使用实例锁 obj
加锁
javaCopy codeObject obj = new Object();
private void a(T t) {
synchronized (obj) { // 使用 obj 作为锁对象
System.out.println(t.s);
// 模拟一些操作,表示持有锁的时间
try {
Thread.sleep(1000); // 暂停线程 1 秒,模拟长时间操作
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
粒度
- 粒度:中等粒度
- 特性:所有调用此方法的线程共享同一个锁
obj
。
优缺点
- 优点:
- 所有线程在调用
a(T t)
方法时必须等待获取同一个锁,确保在任意时刻只有一个线程在执行该方法。 - 容易理解和使用,锁的管理比较简单。
- 所有线程在调用
- 缺点:
- 可能导致性能瓶颈,特别是在高并发情况下,因为所有线程都必须排队等待同一个锁。
- 对于不同的
T
实例,无法利用并发性。
3. 使用静态锁 static Object obj
javaCopy codestatic Object obj = new Object();
private void a(T t) {
synchronized (obj) { // 使用 obj 作为锁对象
System.out.println(t.s);
// 模拟一些操作,表示持有锁的时间
try {
Thread.sleep(1000); // 暂停线程 1 秒,模拟长时间操作
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
粒度
- 粒度:粗粒度
- 特性:所有实例共享同一个静态锁
obj
。
优缺点
- 优点:
- 适用于需要跨实例保护共享资源的情况,确保所有线程在任何
Example
类的实例中执行a(T t)
方法时都互斥。
- 适用于需要跨实例保护共享资源的情况,确保所有线程在任何
- 缺点:
- 性能问题同样存在,所有线程需要等待同一个锁,导致潜在的性能瓶颈。
- 在高并发场景中,可能导致不必要的线程阻塞。
4. 使用无锁 synchronized
(块)
javaCopy codeprivate void a(T t) {
synchronized { // 错误的用法
System.out.println(t.s);
// 模拟一些操作,表示持有锁的时间
try {
Thread.sleep(1000); // 暂停线程 1 秒,模拟长时间操作
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
粒度
- 粒度:无粒度(错误的用法)
- 特性:这段代码是错误的,因为
synchronized
必须要有一个锁对象,不能单独使用。
优缺点
- 优点:
- 无法列出,因为这段代码无法编译和运行。
- 缺点:
- 编译错误,无法使用。
5. 使用类锁 Example.class
javaCopy codeprivate void a(T t) {
synchronized (Example.class) { // 使用类锁
System.out.println(t.s);
// 模拟一些操作,表示持有锁的时间
try {
Thread.sleep(1000); // 暂停线程 1 秒,模拟长时间操作
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
粒度
- 粒度:粗粒度
- 特性:所有
Example
类的实例在调用该方法时都会使用Example.class
锁。
优缺点
- 优点:
- 保证了所有线程对同一类的实例在调用
a(T t)
方法时互斥,确保了线程安全。 - 类锁适用于需要控制对类级资源的访问。
- 保证了所有线程对同一类的实例在调用
- 缺点:
- 性能瓶颈,所有线程在访问此类的实例时必须等待同一个锁,特别是在高并发情况下。
- 可能导致不必要的线程阻塞。
总结
锁类型 | 粒度 | 优点 | 缺点 |
---|---|---|---|
t.s | 细粒度 | 提高并发性,不同 T 实例之间可以并发访问。 | 如果多个 T 实例的 s 字段相同,则可能竞争锁。 |
obj | 中等粒度 | 确保在同一时刻只有一个线程执行,易于理解。 | 性能瓶颈,所有线程竞争同一个锁。 |
static obj | 粗粒度 | 确保跨实例的互斥,适合类级别的共享资源。 | 性能瓶颈,所有线程等待同一个锁。 |
无锁 synchronized | 无粒度 | N/A | 编译错误,无法使用。 |
Example.class | 粗粒度 | 保证所有线程在访问同一类的实例时互斥,适用于类级别的资源保护。 | 性能瓶颈,导致不必要的线程阻塞。 |
在选择锁策略时,应根据具体应用场景和需求来决定,平衡性能和线程安全的需求。细粒度锁通常在并发访问较高的情况下能够提供更好的性能,而粗粒度锁则更易于管理和理解。