语法
无锁情况
package cn.meowrain;
public class Main {
static int count = 0;
static Object lock = new Object();
public static void main(String[] args) {
getResult();
}
static void getResult() {
Thread thread1 = new Thread(() -> {
for (int i = 1; i <= 10000; i++) {
count++;
}
}, "thread1");
Thread thread2 = new Thread(() -> {
for (int i = 1; i <= 1000; i++) {
count--;
}
});
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(count);
}
}
有锁情况
package cn.meowrain;
public class Main {
static int count = 0;
static Object lock = new Object();
public static void main(String[] args) {
getResult();
}
static void getResult() {
Thread thread1 = new Thread(() -> {
synchronized (lock) {
for (int i = 1; i <= 10000; i++) {
count++;
}
}
}, "thread1");
Thread thread2 = new Thread(() -> {
synchronized (lock) {
for (int i = 1; i <= 1000; i++) {
count--;
}
}
});
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(count);
}
}
package cn.meowrain;
public class Main {
public static void main(String[] args) {
Counter counter = new Counter();
Thread t1 = new Thread(()->{
for (int i = 0;i<100000;i++) {
counter.increment();
}
});
Thread t2 = new Thread(()->{
for(int i = 0;i<10000;i++) {
counter.decrement();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
}catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(counter.getCount());
}
}
class Counter {
int count = 0;
public void increment() {
synchronized (this) {
count++;
}
}
public void decrement() {
synchronized (this) {
count--;
}
}
public int getCount() {
synchronized (this) {
return count;
}
}
}
面向对象优化
synchronized
对象上的synchronized
package cn.meowrain;
public class Main {
public static void main(String[] args) {
Counter counter = new Counter();
Thread t1 = new Thread(()->{
for (int i = 0;i<100000;i++) {
counter.increment();
}
});
Thread t2 = new Thread(()->{
for(int i = 0;i<10000;i++) {
counter.decrement();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
}catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(counter.getCount());
}
}
class Counter {
int count = 0;
public void increment() {
synchronized (this) {
count++;
}
}
public void decrement() {
synchronized (this) {
count--;
}
}
public int getCount() {
synchronized (this) {
return count;
}
}
}
加到成员方法上
等价与锁当前对象
加到静态方法上
等价于锁类对象
我的理解很简单,一个是对象锁,一个是类锁
package cn.meowrain;
public class Main {
public static void main(String[] args) {
Counter counterA = new Counter(); // 计数器 A
Counter counterB = new Counter(); // 计数器 B
Counter2.reset(); // 重置静态计数器
// 启动线程操作成员方法锁
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
counterA.increment(); // 操作计数器 A
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
counterB.decrement(); // 操作计数器 B
}
});
// 启动线程操作静态方法锁
Thread thread3 = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
Counter2.increment(); // 操作类级计数器
}
});
Thread thread4 = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
Counter2.decrement(); // 操作类级计数器
}
});
// 启动线程
thread1.start();
thread2.start();
thread3.start();
thread4.start();
// 等待线程完成
try {
thread1.join();
thread2.join();
thread3.join();
thread4.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 输出结果
System.out.println("Counter A value: " + counterA.getCount()); // 独立的 Counter A
System.out.println("Counter B value: " + counterB.getCount()); // 独立的 Counter B
System.out.println("Counter2 (class-based) value: " + Counter2.getCount()); // 全局静态 Counter2
}
}
// 成员方法锁的计数器
class Counter {
int count = 0;
/**
* 给成员方法加锁,锁定的是每个独立实例
*/
public synchronized void increment() {
count++;
}
public synchronized void decrement() {
count--;
}
public synchronized int getCount() {
return count;
}
}
// 静态方法锁的计数器
class Counter2 {
private static int count = 0;
/**
* 加锁静态方法,锁定的是类对象(全局)
*/
public synchronized static void increment() {
count++;
}
public synchronized static void decrement() {
count--;
}
public synchronized static int getCount() {
return count;
}
public static void reset() {
count = 0;
}
}
用上面这个例子就能说明这个。我们可以看到new 一个Counter,计数器就会重置,也就是每个Counter对象有自己的count,而synchronized加到静态方法上,会让Counter2被全局共享
对象锁(Instance-Level Lock)
代码中对应部分:
在 Counter
类中,你对实例方法(increment
、decrement
和 getCount
)使用了 synchronized
关键字:
public synchronized void increment() {
count++;
}
- 这里的
synchronized
是针对对象实例加锁,锁定的范围是调用该方法的当前实例 (this
)。 - 当一个线程调用某个
Counter
对象(如counterA
)的increment
方法时,这个对象会被锁住,其他调用它的线程就必须等待它释放锁资源。但是,不会影响其他实例(如counterB
)。
在你的代码中场景:
Thread thread1
调用的是counterA.increment()
,因此仅锁定counterA
对象。Thread thread2
调用的是counterB.decrement()
,因此仅锁定counterB
对象。
因为 counterA
和 counterB
是两个独立对象(实例),线程对不同对象操作时互不干扰。每个对象都有自己独立的锁。
类锁(Class-Level Lock)
代码中对应部分:
在 Counter2
类中,你对静态方法使用了 synchronized
关键字:
public synchronized static void increment() {
count++;
}
- 这里的
synchronized
是针对类本身加锁,而不是具体的某个对象。锁定的范围是Counter2.class
对象(这个类的字节码对象,是 JVM 中唯一的)。 - 也就是说,无论哪个线程调用
Counter2
的increment
或decrement
方法,只能有一个线程持有该锁资源,其他线程需要等待锁释放。
在你的代码中场景:
Thread thread3
调用的是Counter2.increment()
,此时会锁定Counter2
类对象。Thread thread4
调用的是Counter2.decrement()
,它需要等到thread3
释放Counter2.class
的锁。
所有线程在调用 synchronized
静态方法时,都是竞争类级别的锁,无论静态方法是什么。
对象锁与类锁关键区别
特性 | 对象锁(成员方法加锁) | 类锁(静态方法加锁) |
---|---|---|
锁范围 | 当前对象实例(this ) |
整个类(Class对象 ) |
是否共享 | 不共享,独立 | 共享,所有线程竞争同一个类锁 |
场景 | 每个对象独立的线程安全操作 | 全局共享资源的线程安全操作 |
你的例子 | Counter 的锁只作用在 counterA 和 counterB 上分别独立运行 |
Counter2 的锁作用在全局共享的静态计数器上 |
为什么用这个例子解释得很清楚?
-
对象锁(Counter 类)
- 由于
counterA
和counterB
是独立的对象实例,你可以看到这些计数器的值是独立的,互不干扰。 counterA.increment()
与counterB.decrement()
遵循线程安全,但它们之间没有冲突。
- 由于
-
类锁(Counter2 类)
Counter2
中的静态方法,无论多少线程调用,无论它们在哪,都共享一个全局锁。- 多线程对同一个共享计数器操作时,结果是一致和安全的。
输出分析(代码执行后的结果):
counterA.getCount()
和counterB.getCount()
会显示两个独立的计数值,因为它们是两个独立对象。Counter2.getCount()
则可能显示最终的累加结果(由于所有线程竞争的是同一个类锁)。