Java中synchronized 修饰在 static方法和 非static方法的区别

本文深入探讨了Java中synchronized关键字的使用方式及其背后的锁机制。通过对比静态方法和实例方法的锁行为,揭示了如何实现类下所有方法共享同一把锁的技巧。

Java中synchronized是用来表示同步的,synchronized可以用来修饰一个方法(static方法和非static方法),也可以用来修饰一段代码块;
看代码:

    public synchronized void x() throws InterruptedException {
        for (int i = 0; i < 5; i++) {
            Thread.sleep(1000);
            System.out.println("====x======");
        }
    }

    public static synchronized void staticX() throws InterruptedException {
        for (int i = 0; i < 5; i++) {
            Thread.sleep(1000);
            System.out.println("=======staticX=====");
        }
    }

static的方法属于类方法,它属于这个Class(注意:这里的Class不是指Class的某个具体对象),那么static获取到的锁,是属于类的锁。而非static方法获取到的锁,是属于当前对象的锁。所以,他们之间不会产生互斥。

main方法:

    public static void main(String[] args) {
        final Test1 test1 = new Test1();
        Thread thread1 = new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                try {
                    test1.x();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }, "a");

        Thread thread2 = new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                try {
                    Test1.staticX();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }, "b");
        thread1.start();
        thread2.start();
    }

运行结果:

====x======
=======staticX=====
=======staticX=====
====x======
=======staticX=====
====x======
====x======
=======staticX=====
====x======
=======staticX=====

那当我们想让所有这个类下面的方法都同步的时候,也就是让所有这个类下面的静态方法和非静态方法共用同一把锁的时候,我们如何办呢?

代码如下:

package test;

public class Test2 {
    //创建一个对象  
    final static Test2 ce = new Test2();

    public static void staticX() throws Exception {
        /**
         * 此处的synchronized 和下面的 x()中的synchronized它们调用的都是同一对象‘ce’,
         * 那么此时Test2中的两个方法(所有的方法),公用的都是同一把锁 
         */
        synchronized (ce) {
            for (int i = 0; i < 5; i++) {
                Thread.sleep(1000);
                System.out.println("=======staticX=====");
            }
        }
    }

    public void x() throws Exception {
        synchronized (ce) {
            for (int i = 0; i < 5; i++) {
                Thread.sleep(1000);
                System.out.println("=======x=====");
            }
        }
    }

    public static void main(String[] args) {
        final Test2 test1 = new Test2();
        Thread thread1 = new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                try {
                    test1.x();
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }, "a");

        Thread thread2 = new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                try {
                    Test2.staticX();
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }, "b");
        thread1.start();
        thread2.start();
    }

}

运行结果:

=======x=====
=======x=====
=======x=====
=======x=====
=======x=====
=======staticX=====
=======staticX=====
=======staticX=====
=======staticX=====
=======staticX=====
### synchronized关键字在静态方法中的作用 在 Java 中,`synchronized` 关键字可以用于修饰静态方法。当一个静态方法被 `synchronized` 修饰时,它会锁定该类的**类对象(Class 对象)**,而不是某个具体的实例对象。这意味着多个线程在访问该类的不同实例的同步静态方法时,依然会受到同步控制,因为它们共享同一个类级别的锁 [^2]。 例如,以下代码展示了 `synchronized` 修饰静态方法的情况: ```java class A { public static synchronized void a() { System.out.println("Method a()"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } public static synchronized void b() { System.out.println("Method b()"); } } ``` 在这个类中,如果两个线程分别调用 `A.a()` `A.b()`,由于这两个方法共享同一个类锁,因此它们的执行是串行化的,不能同时进行 。 与静态同步方法不同,静态方法的锁对象是当前实例(`this`),而静态方法的锁对象是类的 `Class` 对象(如 `A.class`)。这种机制确保了类级别的同步,适用于需要保护类级别资源的场景 [^1]。 ### synchronized关键字在静态方法中的有效性 `synchronized` 关键字在静态方法中是有效的,并且具有明确的语义。当一个线程调用某个类的同步静态方法时,它必须先获取该类的 `Class` 对象的锁;如果锁已被其他线程占用,则当前线程会被阻塞,直到锁被释放 [^1]。 以下是一个多线程访问同步静态方法的示例: ```java public class StaticSyncDemo { public static synchronized void task() { System.out.println(Thread.currentThread().getName() + " is running"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " finished"); } public static void main(String[] args) { Thread t1 = new Thread(StaticSyncDemo::task, "Thread-1"); Thread t2 = new Thread(StaticSyncDemo::task, "Thread-2"); t1.start(); t2.start(); } } ``` 上述代码中,两个线程调用的是同一个类的同步静态方法 `task()`,因此它们会按照锁的获取顺序依次执行,而不是并发执行 [^3]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值