欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

从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);
 
未完待续...