线程安全一

说起线程安全,我们第一时间想到的就是加锁,通过锁来保证同一时间只有一个线程访问。最常使用的就是synchronized和lock关键字,以下是我对于使用这两个锁的一些总结。

synchronized

1.锁的对象

我们先来看下面这一段代码

public class Test {

    private String str;

    public Test(String str){
        this.str = str;
    }
    
    public void print(){
        //1
        synchronized (str){
            System.out.println(str);
        }
    }

    //2
    public synchronized void println(){
        System.out.println(str);
    }

    //3
    public static synchronized void print(String str){
        System.out.println(str);
    }

}

这是我们经常使用的几种方法,
第一处可以很明显的看出,锁的对象是str;
第二处修饰的是实例方法,锁的对象是对应的实例,例如

Test t = new Test("str");
t.println();

此时println方法锁的是对象t;
第三处修饰的是类方法,锁的对象是Class对象,此时锁的是Test.class。

2.锁的性质

1)可重入
synchronized是可重入锁,即对于同一个线程,不会出现自己把自己锁死的情况,同步块在已进入的线程执行完之前,会阻塞后面其他的线程。
2)非公平
有若干个线程在等待同一个锁,当锁被释放的时候,这些线程都有机会获得锁,而并非按照时间先后顺序获得。
3)注意的点
synchronized是一个重量级的锁,每次加锁都需要从用户态转到核心态,对于一些简单的操作,有可能转换的时间会比操作执行的时间还要长,所以使用起来需要慎重。

lock

1.常见的用法

Lock lock = new ReentrantLock();
lock.lock();
try{

}catch(Exception e){

}finally {
    lock.unlock();
}

需要注意的是,使用lock锁,需要我们自己去维护释放锁,若是不小心忘记了释放,就很容易出现死锁。
lock还提供给了我们一个方法trylock,让我们可以试着去获取锁。

if(lock.tryLock()){
    //do somthing
    lock.unlock();
}else{
    //没有获取到锁
}

此外还有ReadWriteLock,分为读锁和写锁,读锁能够允许多个线程同时访问,而写锁同一时间只允许一个线程访问。

2.锁的性质

1)性能好
lock可以把锁分成读锁和写锁,在一定程度上比synchronized性能要好。不过虚拟机也针对synchronized做了很多的优化,比如加入自选锁和锁消除等等,而且synchronized不需要自己手动释放,也在一定程度上避免了因为代码的逻辑漏洞而产生死锁的风险。

2)公平锁
ReentranLock默认是非公平锁,可以通过带参数的构造函数指定使用公平锁。公平锁就是按照时间的先后顺序获取锁。

Lock lock = new ReentrantLock(true);

3)可重入
lock也是可重入锁。

总结

lock和synchronized都是基于悲观锁的思想而实现的,
悲观锁就是总是认为只要不做正确的同步措施,就一定会出问题,无论数据是否真的会出现竞争,都必须要加锁。而与之对应的就是乐观锁,就是先进行操作,若没有其他线程竞争,那我的操作就成功了,若有其他的线程竞争,产生了冲突,再采取补救的措施。Atomic就是采用的乐观锁的思想实现的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值