线程同步之锁-synchronized

Java程序使用synchronized关键字对一个对象进行加锁:

synchronized保证了代码块在任意时刻最多只有一个线程能执行。

用法如下:

public class Main {
    public static void main(String[] args) throws Exception {
        var add = new AddThread();
        var dec = new DecThread();
        add.start();
        dec.start();
        add.join();
        dec.join();
        System.out.println(Count.count);
    }
}

class Count {
    // 定义一个锁
    public static final Object lock = new Object();
    // 两个线程的共享变量
    public static int count = 0;
}

class AddThread extends Thread {
    public void run() {
        for (int i=0; i<10000; i++) {
            synchronized(Count.lock) {
                Count.count += 1;
            }
        }
    }
}

class DecThread extends Thread {
    public void run() {
        for (int i=0; i<10000; i++) {
            synchronized(Count.lock) {
                Count.count -= 1;
            }
        }
    }
}

它表示用Count.lock实例作为锁,两个线程在执行各自的synchronized(Count.lock) { ... }代码块时,必须先获得锁,才能进入代码块进行。

执行结束后,在synchronized语句块结束会自动释放锁。这样一来,对Count.count变量进行读写就不可能同时进行。上述代码无论运行多少次,最终结果都是0。

synchronized(Count.lock) { // 获取锁
    ...
} // 释放锁

使用synchronized解决了多线程同步访问共享变量的正确性问题。但是,它的缺点是带来了性能下降。因为synchronized代码块无法并发执行。此外,加锁和解锁需要消耗一定的时间,所以,synchronized会降低程序的执行效率。

如何使用synchronized

  1. 找出修改共享变量的线程代码块;
  2. 选择一个共享实例作为锁;
  3. 使用synchronized(lockObject) { ... }

在使用synchronized的时候,不必担心抛出异常。因为无论是否有异常,都会在synchronized结束处正确释放锁。

总结:

  • 多线程同时读写共享变量时,会造成逻辑错误,因此需要通过synchronized同步;
  • 同步的本质就是给指定对象加锁,加锁后才能继续执行后续代码;
  • 注意加锁对象必须是同一个实例;
  • 对JVM定义的单个原子操作不需要同步。

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值