synchronized的几种加锁方式

1、修饰普通方法(锁住的是当前实例对象)

  • 同一个实例调用会阻塞
  • 不同实例调用不会阻塞
public class SynchronizedTest {
   //锁住了本类的实例对象
   public synchronized void test1() {
        try {
            logger.info(Thread.currentThread().getName() + " test1 进入了同步方法");
            Thread.sleep(5000);
            logger.info(Thread.currentThread().getName() + " test1 休眠结束");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        SynchronizedTest st = new SynchronizedTest();
        SynchronizedTest st2 = new SynchronizedTest();
        new Thread(() -> {
            logger.info(Thread.currentThread().getName() + " test 准备进入");
            st.test1();
        }).start();
        new Thread(() -> {
            logger.info(Thread.currentThread().getName() + " test 准备进入");
            st2.test1();
        }).start();

    }
}

此处列举的是不同实例调用的情况 

2、同步代码块传参this(锁住的是当前实例对象)

  • 同一个实例调用会阻塞
  • 不同实例调用不会阻塞
public class SynchronizedTest {
   //锁住了本类的实例对象
    public void test2() {
        synchronized (this) {
            try {
                logger.info(Thread.currentThread().getName() + " test2 进入了同步块");
                Thread.sleep(5000);
                logger.info(Thread.currentThread().getName() + " test2 休眠结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        SynchronizedTest st = new SynchronizedTest();
        new Thread(() -> {
            logger.info(Thread.currentThread().getName() + " test 准备进入");
            st.test2();
        }).start();
        new Thread(() -> {
            logger.info(Thread.currentThread().getName() + " test 准备进入");
            st.test2();
        }).start();

    }
}

此处列举的是同一实例调用的情况 

3、同步代码块传参变量对象 (锁住的是变量对象)

  • 同一个属性对象才会实现同步
public class SynchronizedTest {
    
   public Integer lockObject;

    public SynchronizedTest(Integer lockObject) {
        this.lockObject = lockObject;
    }

   //锁住了实例中的成员变量
    public void test3() {
        synchronized (lockObject) {
            try {
                logger.info(Thread.currentThread().getName() + " test3 进入了同步块");
                Thread.sleep(5000);
                logger.info(Thread.currentThread().getName() + " test3 休眠结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        SynchronizedTest st = new SynchronizedTest(127);
        SynchronizedTest st2 = new SynchronizedTest(127);
        new Thread(() -> {
            logger.info(Thread.currentThread().getName() + " test 准备进入");
            st.test3();
        }).start();
        new Thread(() -> {
            logger.info(Thread.currentThread().getName() + " test 准备进入");
            st2.test3();
        }).start();

    }
}

同一个实例对象的成员属性肯定是同一个,此处列举的是不同实例的情况,但是 依旧实现了同步,原因如下:

Integer存在静态缓存,范围是-128 ~ 127,当使用Integer A = 127 或者 Integer A = Integer.valueOf(127) 这样的形式,都是从此缓存拿。如果使用 Integer A = new Integer(127),每次都是一个新的对象。此例中,两个对象实例的成员变量 lockObject 其实是同一个对象,因此实现了同步。还有字符串常量池也要注意。所以此处关注是,同步代码块传参的对象是否是同一个。这跟第二个方式其实是同一种。

4、同步代码块传参class对象(全局锁)

  •  所有调用该方法的线程都会实现同步

public class SynchronizedTest {

   //全局锁,类是全局唯一的
    public void test4() {
        synchronized (SynchronizedTest.class) {
            try {
                logger.info(Thread.currentThread().getName() + " test4 进入了同步块");
                Thread.sleep(5000);
                logger.info(Thread.currentThread().getName() + " test4 休眠结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        SynchronizedTest st = new SynchronizedTest();
        SynchronizedTest st2 = new SynchronizedTest();
        new Thread(() -> {
            logger.info(Thread.currentThread().getName() + " test 准备进入");
            st.test4();
        }).start();
        new Thread(() -> {
            logger.info(Thread.currentThread().getName() + " test 准备进入");
            st2.test4();
        }).start();
    }
}

结果如下: 

 

5、修饰静态方法(全局锁)

  • 所有调用该方法的线程都会实现同步
public class SynchronizedTest {

   //全局锁,静态方法全局唯一的
    public synchronized static void test5() {
        try {
            logger.info(Thread.currentThread().getName() + " test5 进入同步方法");
            Thread.sleep(5000);
            logger.info(Thread.currentThread().getName() + " test5 休眠结束");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        SynchronizedTest st = new SynchronizedTest();
        SynchronizedTest st2 = new SynchronizedTest();
        new Thread(() -> {
            logger.info(Thread.currentThread().getName() + " test 准备进入");
            st.test5();
        }).start();
        new Thread(() -> {
            logger.info(Thread.currentThread().getName() + " test 准备进入");
            st2.test5();
        }).start();
        new Thread(() -> {
            logger.info(Thread.currentThread().getName() + " test 准备进入");
            SynchronizedTest.test5();
        }).start();
    }
}

 

  • 8
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值