【Java】synchronized的使用

synchronized锁定的资源

synchronized修饰的是方法或者代码块来实现同步,但其实锁定的资源其实是对象synchronized修饰于3种方式(静态方法、普通方法、方法块),其锁定的资源有2种(类对象、类的实例)加synchronized关键字之后不一定能实现线程安全,具体还要看锁定的对象是否唯一

  1. synchronized修饰静态方法,锁定的资源是Class对象(类对象,Class class = x x x.Class)
    两种方式:
public class Demo {
   
    private static int count = 10;
    //synchronize关键字修饰静态方法锁定的是类对象
    //方式1
    public synchronized static void test(){
   
    //临界区
        count--;
    }
    //方式二
    public static void test2(){
   
        synchronized (Demo4.class){
   //这里不能替换成this
        //临界区
            count--;
        }
    }
}
  1. synchronized修饰普通方法,锁定的资源是类的实例(User o = new User())

三种方式:

  • 对象用new的方式
    private int count = 10;
    private Demo reentryDemo = new Demo();
    public void test(){
   
        synchronized (object){
   
            //临界区
            count--;
        }
    }
  • 用this来代替,当前对象的实例
public void test() {
   
  synchronize (this) {
   }
}
  • 直接修饰在普通方法上
public synchronized void test() {
   }
  1. synchronized修饰代码块/方法块,其实实际上也是方法的一部分, 所以锁定的资源也是根据方法来。

锁定对象改变

  1. 如果锁定对象的属性发生改变,不会影响锁的使用。

  2. 如果锁定对象修改为另外一个对象,这种锁定对象的改变了,等于是一把新锁了。
    示例代码:

public class Demo {
   
    public Lock lock = new Lock();
    public void test () {
   
        synchronized (lock) {
   
            while (true) {
   
                try {
   
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
   
                    e.printStackTrace();
                }
                log.debug("hello word");
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
   
        Demo reentryDemo = new Demo();
        new Thread(reentryDemo::test,"t1").start();
        TimeUnit.MILLISECONDS.sleep(10);
//        reentryDemo.lock.i=20;
        reentryDemo.lock = new Lock();
        new Thread(reentryDemo::test,"t2").start();
    }
}
class Lock {
   
    public int i = 0;
}

锁定对象为字符串常量

不要以字符串常量作为锁定的对象,在jvm中两个相同的字符串都是指向常量池同一块内存。

所以虽然名字不同,但实际上还是同一把锁。

    public String sLock1 = "lock";
    public String sLock2 = "lock";
    public void test1 () {
   
        synchronized (sLock1) {
   
            while (true) {
   
                try {
   
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
   
                    e.printStackTrace();
                }
                log.debug("hello word");
            }
        }
    }
    public void test2() {
   
        synchronized (sLock2) {
   
            log.debug("test2 end");
        }
    }

另外一种情况,不属于并发的知识点了。这种就是2个对象了。

public String sLock1 = new String("lock");
public String sLock2 = new String("lock");

减小锁的颗粒度

通过减少同步的代码块,降低锁的颗粒度。同步的代码块越少越好,从而提高效率。

比如说在业务上只要保证count的同步,可以采用细颗粒度的锁,从而减少线程竞争的时间。

优化方案:就只需要对count++局部上锁,不用对整个方法上锁。

Bad:

int count = 0;

public synchronized void test(){
   
    try {
   
        TimeUnit.SECONDS.sleep(2);
    } catch (InterruptedException e) {
   
        e.printStackTrace();
    }

    count ++;

    try {
   
        TimeUnit.SECONDS.sleep(2);
    } catch (InterruptedException e) {
   
        e.printStackTrace(
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值