Synchronized的使用及原理(这篇文章就够了)

前言

平时的开发中,我们经常与多线程接触,有时候某个变量是可以多个线程共享的,那么很有可能就会引入同步问题,使用synchronized关键字,将存在同步问题的代码块或者方法修饰起来,便是我们经常用来解决多线程同步的问题,下面我们一起看看它的使用及原理。

正文

1.同步问题:
private static void test() {
    Runnable task = new Runnable() {
        int count = 10;
        @Override
        public void run() {
          //a
            if (count > 0) {
              //b
                System.out.println("count:" + count);
              //c
            		--count;
            }
        }
    };
    Thread t1 = new Thread(task);
    Thread t2 = new Thread(task);
    t1.start();
    t2.start();
}

像上面的例子,就有可能出现同步问题,比如输出了count:0,这里分析一下为什么会出现同步问题:

如过count=1时,t1线程执行到b处,然后被t2线程抢占了,这个时候t2线程执行完b、c,这时c=0,然后t1恢复了,这时就会输出了count:0,很明显不符合预期。

那么我们如果使用synchronized,那么就可以防止这种情况发生,下面我们一起看看它的使用。

2.synchronized介绍

每个Java对象都可以作为锁,如果有线程访问同步代码,那么会先尝试获取对象锁,等到退出同步代码或者出现异常时才释放掉锁。

3.synchronized的使用场景
  • 同步方法
private synchronized void fun() {
    //
}

同步方法是使用synchronized关键字修饰的方法,同步锁则是这个对象本身,即this。

  • 同步代码块
final Object lock = new Object();

private void fun() {
    synchronized (lock) {
        //
    }
}

同步代码块则需要显式制定锁对象

  • 静态同步方法
private static synchronized void fun() {
    //
}

静态同步方法锁对象则是class对象T.class。

4.原理
  • 同步代码块:编译后,将monitorenter指令插入到代码块的开始处,然后将monitorexit指令插入到代码块结束处或者异常处。每个对象都有一个关联的monitor,当遇到monitorenter时,就需要去获取monitor,获取不到则进入阻塞队列,等待这个monitor被持有者释放后的唤醒通知。
  • 同步方法:在method_info的结构里,有ACC_Sychronized标记,线程执行时如果识别到这个标记,则会去获取对应的锁。

这两者的细节不一样,但是本质上都是尝试获取对象的monitor,如果获取不到,则线程会被阻塞(状态为BLOCKED),进入同步队列。当持有monitor的线程释放了锁后,就会唤醒阻塞在同步队列的线程,然后大家重新尝试获取monitor。
在这里插入图片描述

5.特性
  • 重入锁

当一个线程获得对象锁时,可以再一次获取该对象锁,synchronized就支持:

final Object lock = new Object();

private void fun2() {
    synchronized (lock) {
        fun1();
    }
}

private void fun1() {
    synchronized (lock) {
    }
}

以上的fun2获取到lock对象锁后,调用fun1,fun1里边再次获取lock对象锁。

  • 非公平锁

CPU调度线程的时候,会在等待队列中随机选一个线程,这样就没办法保证先到先得,有的线程(优先级比较低)可能永远都没发获取到CPU到执行权,会造成饥饿现象。公平锁就会保证线程按照时间的先后顺序执行,避免饥饿现象的产生。但synchronized控制的锁是非公平锁。

结语

本文的分享到这里就结束了,内容涵盖了synchronized的使用和原理,当然我们在平时的使用中,要合理考量,避免比较粗暴地加上synchronized来防止同步问题,应该需要在合理的粒度上加。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值