十一、guava 并发工具 monitor

    java处理并发时,synchronized语句块中,无论使用对象监视器的wait notify/notifyAll还是Condition的await signal/ signalAll方法调用,我们首先都会对共享数据的临界值进行判断,当条件满足或者不满足的时候才会调用相关方法使得当前线程挂起,或者唤醒wait的线程。

1. wait/notify示例代码

package org.example.model.guava;

import lombok.SneakyThrows;
import org.junit.Test;

import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.IntStream;

public class MonitorTest {
    
    // queue既是队列又是并发监视器
    private LinkedList queue = new LinkedList<>();

    private int maxSize = 2;

    @Test
    public void test() {
        AtomicLong count = new AtomicLong(0);
        
        // 起三个线程向队列添加元素
        IntStream.range(0, 3).forEach(i ->
                new Thread(() -> {
                    while (true) {
                        long value = count.getAndIncrement();
                        offer(value);
                        System.out.println("offer--" + i + ":" + value);
                        sleep(1);
                    }
                }).start());

        // 起三个线程从队列中取元素
        IntStream.range(0, 3).forEach(i ->
                new Thread(() -> {
                    while (true) {
                        long value = take();
                        System.out.println("take---" + i + ":" + value);
                        sleep(1);
                    }
                }).start());

        sleep(100);
    }

    // 向队列中放入值
    @SneakyThrows
    private void offer(long value) {
        synchronized (queue) {
            // 队列满,则wait
            while (queue.size() >= maxSize) {
                queue.wait();
            }

            queue.addLast(value);
            
            // 唤醒所有等待的线程
            queue.notifyAll();
        }
    }

    // 从队列中取值
    @SneakyThrows
    private long take() {
        synchronized (queue) {
            // 队列空,则wait
            while (queue.isEmpty()) {
                queue.wait();
            }

            Long value = queue.removeFirst();
            // 唤醒所有等待的线程
            queue.notifyAll();
            return value;
        }
    }

    @SneakyThrows
    private void sleep(long delay) {
        Thread.sleep(delay);
    }
}

2. Condition的await signal/ signalAll示例

package org.example.model.guava;

import lombok.SneakyThrows;
import org.junit.Test;

import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.IntStream;

public class MonitorTest {
    private LinkedList queue = new LinkedList<>();

    // 可重入锁,并创建两个条件,队列空和队列满
    private ReentrantLock lock = new ReentrantLock();

    private Condition emptyCondition = lock.newCondition();

    private Condition fullCondition = lock.newCondition();
    private int maxSize = 2;

    @Test
    public void test() {
        AtomicLong count = new AtomicLong(0);

        // 起三个线程向队列添加元素
        IntStream.range(0, 3).forEach(i ->
                new Thread(() -> {
                    while (true) {
                        long value = count.getAndIncrement();
                        offer(value);
                        System.out.println("offer--" + i + ":" + value);
                        sleep(1);
                    }
                }).start());

        // 起三个线程从队列中取元素
        IntStream.range(0, 3).forEach(i ->
                new Thread(() -> {
                    while (true) {
                        long value = take();
                        System.out.println("take---" + i + ":" + value);
                        sleep(1);
                    }
                }).start());

        sleep(100);
    }

    // 向队列中放入值
    @SneakyThrows
    private void offer(long value) {
        try {
            lock.lock();
            // 队列满,使用fullCondition进入等待
            while (queue.size() >= maxSize) {
                fullCondition.await();
            }

            queue.addLast(value);

            // 唤醒emptyCondition阻塞的线程
            emptyCondition.signalAll();
        } finally {
            lock.unlock();
        }
    }

    // 从队列中取值
    @SneakyThrows
    private long take() {
        try {
            lock.lock();
            // 队列空,使用emptyCondition进入等待
            while (queue.isEmpty()) {
                emptyCondition.await();
            }

            Long value = queue.removeFirst();

            // 唤醒fullCondition阻塞的线程
            fullCondition.signalAll();
            return value;
        } finally {
            lock.unlock();
        }
    }

    @SneakyThrows
    private void sleep(long delay) {
        Thread.sleep(delay);
    }
}

3. 使用guava monitor

 我们发现无论时wait/notify,还是使用锁的condition的await/signal,都需要在代码中判断满足条件时编写wait/notify, await/signal代码,代码意义不明显,可读性比较差。使用guava monitor能够使得代码的语义性更强,具有更好的可读性。示例如下:

package org.example.model.guava;

import com.google.common.util.concurrent.Monitor;
import lombok.SneakyThrows;
import org.junit.Test;

import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.IntStream;

public class MonitorTest {
    private LinkedList queue = new LinkedList<>();

    private int maxSize = 2;

    private Monitor monitor = new Monitor();

    private Monitor.Guard canOffer = monitor.newGuard(() -> queue.size() <= maxSize);

    private Monitor.Guard canTake = monitor.newGuard(() -> !queue.isEmpty());


    @Test
    public void test() {
        AtomicLong count = new AtomicLong(0);

        // 起三个线程向队列添加元素
        IntStream.range(0, 3).forEach(i ->
                new Thread(() -> {
                    while (true) {
                        long value = count.getAndIncrement();
                        offer(value);
                        System.out.println("offer--" + i + ":" + value);
                        sleep(1);
                    }
                }).start());

        // 起三个线程从队列中取元素
        IntStream.range(0, 3).forEach(i ->
                new Thread(() -> {
                    while (true) {
                        long value = take();
                        System.out.println("take---" + i + ":" + value);
                        sleep(1);
                    }
                }).start());

        sleep(100);
    }

    // 向队列中放入值
    @SneakyThrows
    private void offer(long value) {
        try {
            monitor.enterWhen(canOffer);
            queue.addLast(value);
        } finally {
            monitor.leave();
        }
    }

    // 从队列中取值
    @SneakyThrows
    private long take() {
        try {
            monitor.enterWhen(canTake);
            return queue.removeFirst();
        } finally {
            monitor.leave();
        }
    }

    @SneakyThrows
    private void sleep(long delay) {
        Thread.sleep(delay);
    }
}

你可能感兴趣的:(guava,guava,jvm)