如何解决线程安全问题?

解决方式一(同步代码块)

Object o = new Object();
synchronized (o){//方式二:synchronized (this) { 方式三:synchronized (当前类名.class) {
  //需要被同步的代码(操作共享数据的代码)
}

说明:
1.通过synchronized(锁)来实现线程同步

2.任何一个类的对象都可以充当锁(可以是this,也可以是当前类的对象),在实现Runnable接口创建多线程的方式中,我们可以考虑使用this充当锁。

3.多个线程必须要共用同一把锁。

4.锁的原理:当有线程进入同步代码块之后,利用JVM的计数器会将锁的标记置为1,当别的线程再想进入的时候,发现锁的标记为1, 该线程就会去锁池等待,当第一个线程出来之后,锁的标记会置为0,之后CPU会随机分配一个线程再次进入同步代码块。

解决方式二(同步方法)

//方式一
public synchronized void synchronizedTest(){
     //需要被同步的代码(操作共享数据的代码)
}
//方式二
public static synchronized void synchronizedTest1(){
    //需要被同步的代码(操作共享数据的代码)
}

说明:
1.将操作共享数据的代码完整的声明在一个含synchronized关键字的方法中来实现线程同步

2.依旧涉及到锁,但是不需要我们显式的声明锁

3.两种同步方法的锁:
非静态的同步方法:this
静态的同步方法:当前类本身

解决方式二(Lock锁)

Lock l = new ReentrantLock();
     l.lock();//手动启动锁
     //存在线程安全问题的代码
     l.unlock();//解锁

说明:
1.在需要被同步的代码前手动创建Lock的子类对象启动lock锁,在其后手动解除锁unlock,使没拿到锁的线程等待,但是这种很容易出现死锁。注意加锁以及解锁的顺序,就可以避免死锁。

对比ReentrantLock和Synchronized

一、代码

采用synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用,更安全

而ReentrantLock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。需要lock()和unlock()方法配合try-finally语句块来完成

二、灵活性

Synchronized:锁的范围是整个方法或synchronized块部分

ReentrantLock:Lock因为是方法调用,可以跨方法,灵活性更大

三、等待是否可以被中断

Synchronized:不可中断,除非抛出异常
释放锁方式:
1.代码执行完,正常释放锁。
2.抛出异常,由JVM退出等待。

ReentrantLock:持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待。
方法:
1.设置超时方法 tryLock(long timeout,TimeUnit unit),时间过了就放弃等待。
2.locklnterruptibly()放代码块中,调用interrupt()方法可中断,而synchronized不行。

三、是否是公平锁

Synchronized:非公平锁

ReentrantLock:默认公平锁,构造器可以传入boolean值,true为公平锁,false为非公平

四、适用情况

Synchronized:资源竞争不是很激烈的情况下,偶尔会有同步的情形下, synchronized是很合适的。原因在于,编译程序通常会尽可能的进行优化synchronize,可读性也非常好

ReentrantLock:ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步等。在资源竞争不激烈的情形下,性能肖微比synchronized差一点点。但是当同步非常激烈的时候,synchronized的性能会下降。而ReentrantLock还能维持常态。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Link♛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值