语法

无锁情况

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 类中,你对实例方法(incrementdecrementgetCount)使用了 synchronized 关键字:

public synchronized void increment() {
    count++;
}
  • 这里的 synchronized 是针对对象实例加锁,锁定的范围是调用该方法的当前实例 (this)。
  • 当一个线程调用某个 Counter 对象(如 counterA)的 increment 方法时,这个对象会被锁住,其他调用它的线程就必须等待它释放锁资源。但是,不会影响其他实例(如 counterB)。

在你的代码中场景:

  • Thread thread1 调用的是 counterA.increment(),因此仅锁定 counterA 对象
  • Thread thread2 调用的是 counterB.decrement(),因此仅锁定 counterB 对象

因为 counterAcounterB 是两个独立对象(实例),线程对不同对象操作时互不干扰。每个对象都有自己独立的锁


类锁(Class-Level Lock)

代码中对应部分:

Counter2 类中,你对静态方法使用了 synchronized 关键字:

public synchronized static void increment() {
    count++;
}
  • 这里的 synchronized 是针对类本身加锁,而不是具体的某个对象。锁定的范围是 Counter2.class 对象(这个类的字节码对象,是 JVM 中唯一的)。
  • 也就是说,无论哪个线程调用 Counter2incrementdecrement 方法,只能有一个线程持有该锁资源,其他线程需要等待锁释放。

在你的代码中场景:

  • Thread thread3 调用的是 Counter2.increment(),此时会锁定 Counter2 类对象
  • Thread thread4 调用的是 Counter2.decrement(),它需要等到 thread3 释放 Counter2.class 的锁。

所有线程在调用 synchronized 静态方法时,都是竞争类级别的锁,无论静态方法是什么


对象锁与类锁关键区别

特性 对象锁(成员方法加锁) 类锁(静态方法加锁)
锁范围 当前对象实例(this 整个类(Class对象
是否共享 不共享,独立 共享,所有线程竞争同一个类锁
场景 每个对象独立的线程安全操作 全局共享资源的线程安全操作
你的例子 Counter 的锁只作用在 counterAcounterB 上分别独立运行 Counter2 的锁作用在全局共享的静态计数器上

为什么用这个例子解释得很清楚?

  1. 对象锁(Counter 类)

    • 由于 counterAcounterB 是独立的对象实例,你可以看到这些计数器的值是独立的,互不干扰。
    • counterA.increment()counterB.decrement() 遵循线程安全,但它们之间没有冲突。
  2. 类锁(Counter2 类)

    • Counter2 中的静态方法,无论多少线程调用,无论它们在哪,都共享一个全局锁。
    • 多线程对同一个共享计数器操作时,结果是一致和安全的。

输出分析(代码执行后的结果):

  • counterA.getCount()counterB.getCount() 会显示两个独立的计数值,因为它们是两个独立对象。
  • Counter2.getCount() 则可能显示最终的累加结果(由于所有线程竞争的是同一个类锁)。