JDK下的并发安全问题

201 阅读3分钟

1.JDK下的并发安全问题

如果你是在传统行业待着可能并不会关注到并发安全问题,假如你从事着OA,CRM等系统的开发,这些系统可能访问量并不大,你书写的代码就算有并发安全的漏洞,你也可能发现不到这问题。

所以,要谈来并发安全的问题,最好的方式并不是一来就谈解决方案,而是先把并发安全的问题重新

2.场景重现


在讨论并发安全问题解决方案之前,先把这问题重现了

看上面这个图,要产生并发安全问题:有几个事情是应该同时发生的:

  1. 有很多用户(并发场景)

  2. 对同一共享资源进行操作

2.1.并发重现

OrderNumGenerator负责生成订单ID,而FileId.nextId的方法是写一个文件,取出文件里面最新的数字,然后+1, 获得结果写入原来的文件,再返回数据(这一步涉及IO的读写操作会占用很多时间,很容易产生并发安全问题)

下面是测试类

模拟50个并发,同时生成订单ID,排序后看输出的结果

可以看出最终的结果里面有大量的重复,如果在真实的项目开发中,这会发生很严重的问题

3.使用Synchronized解决方案

3.1.解决原理


3.2.解决代码

package cn.enjoy.syn;

import java.text.SimpleDateFormat;

import java.util.Date;

public class OrderNumGenerator {

//全局订单id

public static int count = 0;

public static Object lock = new Object();

public String getNumber() {

synchronized(lock){

SimpleDateFormat simpt = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");

return simpt.format(new Date()) + "-" + ++count/+"_"+Thread.currentThread().getId()/;

}

}

}

4.Lock解决方案

4.1.解决原理

4.2.解决代码

package cn.enjoy.lock;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.concurrent.locks.ReentrantLock;

public class OrderNumGenerator {

//全局订单id

public static int count = 0;

private java.util.concurrent.locks.Lock lock = new ReentrantLock();

//以lock的方式解决

public String getNumber() {

try {

lock.lock();

SimpleDateFormat simpt = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");

String s = simpt.format(new Date()) + "-" + ++count;

return s;

}finally {

lock.unlock();

}

}

}

5.谈一个面试题

Synchronized与Lock 都能解决并发安全问题,但他们有哪些区别呢?

Lock接口比同步方法和同步块提供了更具扩展性的锁操作。

他们允许更灵活的结构,可以具有完全不同的性质,并且可以支持多个相关类的条件对象。

它的优势有:可以使锁更公平,可以使线程在等待锁的时候响应中断,可以让线程尝试获取锁,并在无法获取锁的时候立即返回或者等待一段时间,可以在不同的范围,以不同的顺序获取和释放锁。

整体上来说Lock是synchronized的扩展版,Lock提供了无条件的、可轮询的(tryLock方法)、定时的(tryLock带参方法)、可中断的(lockInterruptibly)、可多条件队列的(newCondition方法)锁操作。另外Lock的实现类基本都支持非公平锁(默认)和公平锁,synchronized只支持非公平锁,当然,在大部分情况下,非公平锁是高效的选择。

通过这些描述,总结出来,区别如下:

  1. Lock提供更灵活的功能

  2. Lock可以实现公平锁的功能,如下图

6.总结

其实并发安全解决起来并不复杂,这问题难在发现这个问题,如果你根本就没有重视这问题,可能在项目运行过程中绝多数情况下是正确的,但如果出现了并发安全问题,可能会很大的损失。

但现在讨论的是单节点下的并发安全问题(一个JVM),但在分布式场景下可能又会出现新的问题,那这里说的问题是什么呢?