从demo到支持高并发
程序员文章站
2022-04-19 08:22:52
...
前言:
Java语言作用很大,因有众多分门杂类的开源框架导致Javaer关注高并发细节问题偏少,常常被面试或者面试的时候,别人总是问你current的包,但是却很少人会询问你,“这段代码在高并发的情况下,会出现问题?我们应该如何改写呢?”所以本篇博客我想从最简单的demo,到支持高并发场景的,如果觉得过程中有问题问大家赐教。
案例:
经典多线程并发问题就是生产者消费者问题,以下列子中,我会加入多种条件,而非一个纯种的生产者-消费者模式,可能很多人会觉得现在有了concurrent的PKG下的一大堆ArrayBlockQueue,但今天主题是如何优化改进。
demo,非安全的
public class UserAccount { private int balance; private long maxMoney = 5000000; private long minMOney = 1000000; public UserAccount(int balance) { this.balance = balance; } public void deposit(int amount) { while (balance + amount < maxMoney) { balance += amount; System.out.printf("存:" + balance); } } public void withdraw(int amount) { while (minMOney > balance - amount) { balance -= amount; System.out.println("取:" + balance); } } }
第一步: 上面的代码很明显会出现并发问题,简单点我们加入synchronized
public class UserAccount { private int balance; private long maxMoney = 90000000; private long minMOney = 1000000; public UserAccount(int balance) { this.balance = balance; } public synchronized void deposit(int amount) { // synchronized (this) { while (balance + amount < maxMoney) { balance += amount; System.out.println("存:" + balance); } } // } public synchronized void withdraw(int amount) { while (minMOney > balance - amount) { balance -= amount; System.out.println("取:" + balance); } } }第二步:有没有发现加入关键字synchronized后,是并发问题解决了,但是我们锁的范围太广了,不懂得可以看下synchronized的说明。(当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行)
public void deposit(int amount) { synchronized (this) { while (balance + amount < maxMoney) { balance += amount; System.out.println("存:" + balance); } } }第四步:实际过程中,往往我们不会只有一个条件,这时候使用到ReentrantLock
private final Lock monitor = new ReentrantLock(); private final Condition low = monitor.newCondition(); private final Condition high = monitor.newCondition(); public UserAccount(int balance) { this.balance = balance; } public void deposit(int amount) { monitor.lock(); try { while (balance + amount < maxMoney) { balance += amount; System.out.println("存:" + balance); } low.signal(); } finally { monitor.unlock(); } }第五步:锁升级,加入读写锁ReentrantReadWriteLock
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void read() { lock.readLock().lock(); System.out.println(balance); lock.readLock().unlock(); }
第六步:使用Atomic原子类
第七步:使用violate
假设你的资源类中violate修饰的变量读的频繁程度远远大于写,那么violate修饰的变量就派上用场。
private volatile int value; public int getValue() { return value; } public int increment() { synchronized (this) { return value++; } }
第八步 异步处理
CompletableFuture.supplyAsync(() -> {do something();}, taskExecutor);
未完待续...
上一篇: 配置ThreadPoolExecutor
下一篇: Spring事务不起作用 问题汇总