Contenedores y herramientas concurrentes de subprocesos múltiples de Java

Tres, contenedores y herramientas concurrentes

1. Contenedores concurrentes

【1】 ConcurrentHashMap

HashMap en el caso de multiproceso. Tenga en cuenta que ni KEY ni VALUE pueden ser nulos

【2】ConcurrentSkipListMap

TreeMap en multiproceso

ConcurrentSkipListMap<String, Integer> concurrentSkipListMap = new ConcurrentSkipListMap<String, Integer>();
concurrentSkipListMap.put("a", 1);
concurrentSkipListMap.put("A", 2);
concurrentSkipListMap.put("0", 3);
concurrentSkipListMap.put("b", 4);
System.out.println(concurrentSkipListMap); // {0=3, A=2, a=1, b=4}

System.out.println("0-" + (int)'0'); // 0-48
System.out.println("A-" + (int)'A'); // A-65
System.out.println("a-" + (int)'a'); // a-97
System.out.println("b-" + (int)'b'); // b-98

【3】 ConcurrentSkipListSet

TreeSet en multiproceso

【4】 CopyOnWriteArrayList

ArrayList en el caso de subprocesos múltiples. Bloqueos para operaciones de escritura y sin bloqueos para operaciones de lectura, lo que garantiza el rendimiento.

Matriz de Objetos modificados volátiles, cada vez que se modifica la matriz, se creará una nueva matriz y la referencia se apuntará a ella

Por ejemplo, addoperación:

public boolean add(E e) {
    
    
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
    
    
        Object[] elements = getArray();
        int len = elements.length;
        Object[] newElements = Arrays.copyOf(elements, len + 1); // 创建新的数组
        newElements[len] = e;
        setArray(newElements); // 指向新的数组
        return true;
    } finally {
    
    
        lock.unlock();
    }
}

【5】 CopyOnWriteArraySet

Una CopyOnWriteArrayList se mantiene internamente

private final CopyOnWriteArrayList<E> al;

Antes de agregar un nuevo elemento, primero determinará si el elemento ya existe, y si no se encuentra, se guardará en el contenedor.

/**
 * java.util.concurrent.CopyOnWriteArrayList#addIfAbsent(E)方法
 */
public boolean addIfAbsent(E e) {
    
    
    Object[] snapshot = getArray();
    return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
    addIfAbsent(e, snapshot);
}

2. Herramientas de concurrencia

【1】 CountdownLatch

Pestillo de cuenta regresiva. Dar el valor estadístico de antemano y restar 1 cada vez, cuando se reduzca a 0, suelte

CountDownLatch countDownLatch = new CountDownLatch(2);

new Thread(() -> {
    
    
    System.out.println("A");
    try {
    
    
        Thread.sleep(500);
    } catch (InterruptedException e) {
    
    
        e.printStackTrace();
    }
    countDownLatch.countDown(); // 减1
}).start();

new Thread(() -> {
    
    
    System.out.println("B");
    try {
    
    
        Thread.sleep(1000);
    } catch (InterruptedException e) {
    
    
        e.printStackTrace();
    }
    countDownLatch.countDown(); // 减1
}).start();

try {
    
    
    countDownLatch.await(); // Main线程等待
} catch (InterruptedException e) {
    
    
    e.printStackTrace();
}

System.out.println("结束!");

【2】 CyclicBarrier

Barrera de circulación. Dé el valor estadístico por adelantado, agregue 1 cada vez, cuando se agregue el valor estadístico, suelte

Utilice el método uno:

public static void main(String[] args) {
    
    
    CyclicBarrier cyclicBarrier = new CyclicBarrier(3); // 记得算上Main线程

    new Thread(() -> {
    
    
        System.out.println("A");
        try {
    
    
            Thread.sleep(500);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        try {
    
    
            cyclicBarrier.await(); // 等待(加1)
        } catch (InterruptedException | BrokenBarrierException e) {
    
    
            e.printStackTrace();
        }
    }).start();

    new Thread(() -> {
    
    
        System.out.println("B");
        try {
    
    
            Thread.sleep(1000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        try {
    
    
            cyclicBarrier.await(); // 等待(加1)
        } catch (InterruptedException | BrokenBarrierException e) {
    
    
            e.printStackTrace();
        }
    }).start();

    try {
    
    
        cyclicBarrier.await(2, TimeUnit.SECONDS); // 只等待2秒钟(加1)
    } catch (InterruptedException | BrokenBarrierException | TimeoutException e) {
    
    
        e.printStackTrace();
    }

    System.out.println("结束!");
}

Uso 2:

CyclicBarrier cyclicBarrier = new CyclicBarrier(2, () -> {
    
    
    System.out.println("结束!");
}); // 其他线程都执行完毕后,执行该线程方法

new Thread(() -> {
    
    
    System.out.println("A");
    try {
    
    
        Thread.sleep(500);
    } catch (InterruptedException e) {
    
    
        e.printStackTrace();
    }
    try {
    
    
        cyclicBarrier.await(); // 等待(加1)
    } catch (InterruptedException | BrokenBarrierException e) {
    
    
        e.printStackTrace();
    }
}).start();

new Thread(() -> {
    
    
    System.out.println("B");
    try {
    
    
        Thread.sleep(1000);
    } catch (InterruptedException e) {
    
    
        e.printStackTrace();
    }
    try {
    
    
        cyclicBarrier.await(); // 等待(加1)
    } catch (InterruptedException | BrokenBarrierException e) {
    
    
        e.printStackTrace();
    }
}).start();

【3】 Semáforo

señal. Especifique el número de subprocesos que se pueden ejecutar a la vez

int loop = 10;
int permits = 2;

ExecutorService executorService = Executors.newFixedThreadPool(loop);
Semaphore semaphore = new Semaphore(permits);

for (int i = 0; i < loop; i++) {
    
    
    executorService.execute(() -> {
    
    
        try {
    
    
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName() + " ---> 执行任务");
            Thread.sleep(3000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            semaphore.release();
        }
    });
}

if (!executorService.isShutdown()) {
    
    
    executorService.shutdown();
}

【4】 Intercambiador

Intercambiador. Se utiliza para el intercambio de datos entre hilos. Si un hilo inicia el intercambio, siempre esperará a que otro hilo lo realice. Si tiene miedo de esperar demasiado, puede utilizar el public V exchange(V x, long timeout, TimeUnit unit) throws InterruptedException, TimeoutExceptionmétodo

Exchanger<String> exchanger = new Exchanger<String>();
new Thread(() -> {
    
    
    try {
    
    
        System.out.println(Thread.currentThread().getName() + "发出了消息,等待回复");

        String exchange = exchanger.exchange("hello?");
        Thread.sleep(2000);
        System.out.println(Thread.currentThread().getName() + "收到了:" + exchange);
    } catch (InterruptedException e) {
    
    
        e.printStackTrace();
    }
}, "线程A").start();

new Thread(() -> {
    
    
    try {
    
    
        Thread.sleep(3000);

        String exchange = exchanger.exchange("hi!");
        System.out.println(Thread.currentThread().getName() + "收到了:" + exchange + ",并且已回复");
    } catch (InterruptedException e) {
    
    
        e.printStackTrace();
    }
}, "线程B").start();

Supongo que te gusta

Origin blog.csdn.net/adsl624153/article/details/103865261
Recomendado
Clasificación