liujijiang

java学习笔记 --21-- 并发(5)

2020.04.19

PriorityBlockingQueue

其中的任务按照优先级顺序从队列中出来

Semaphore(信号量)

正常的锁(synchronized和Lock)只允许同时有一个任务访问资源

信号量:允许n个任务访问资源

Exchanger

两个任务之间交换对象的栅栏

可以让对象在创建的同时被消费

性能调优

Lock通常比synchronized更高效

synchronized代码简单易读

写代码使用synchronized,调优的时候改成Lock

免锁容器

hashTable和Vector有很多synchronized方法

免锁容器通用策略:读取和写入可以同时发生
在CopyOnWriteArrayList中,写入操作:现有数据复制一个副本,写入操作写给副本,然后一个原子性的替换工作完成全部的写入工作,所以在写入过程中仍然可以读,读的是写入之前的数据

CopyOnWriteSet使用CopyOnWriteArrayList来实现免锁行为

ConcurrentHashMap和ConcurrentLinkedQueue也使用了类似的技术,允许并发写入和读取,在写入完全完成之前读取的仍然是写入之前的数据

乐观锁

只要你使用免锁容器读取就比synchronized的产物快很多,因为省去了加锁和解锁的操作

List

synchronized:无论读取和写入多少次,性能差不多
CopyOnWriteArrayList:如果没有写入,性能很高,即使有写入操作,性能还是比synchronized的产物高

Map

向ConcurrentHashMap添加写入操作对其产生的影响比CopyOnWriteArrayList还小

乐观加锁

使用Atomic能带来性能上的收益
乐观:保持数据为未锁定状态

package com.atomicTest;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author redarm
 * @Date 2020/4/19 8:37 上午
 **/
public class FastSimulation {
    static final int N_ELEMENTS = 100000;
    static final int N_GENES = 30;
    static final int N_EVOLVERS = 50;

    static final AtomicInteger [] [] GRID = new AtomicInteger[N_ELEMENTS][N_GENES];
    static Random random = new Random(1);

    static class Evolver implements Runnable{
        @Override
        public void run() {
            while (!Thread.interrupted()){
                int element = random.nextInt(N_ELEMENTS);
                for(int i=0;i<N_GENES;i++){
                    int previous = element - 1;
                    if (previous < 0)
                        previous = N_ELEMENTS-1;
                    int next = element + 1;
                    if (next >= N_ELEMENTS)
                        next = 0;
                    int odvalue = GRID[element][i].get();

                    int newvValue = odvalue + GRID[previous][i].get()+GRID[next][i].get();
                    newvValue /= 3;

                    if(!GRID[element][i].compareAndSet(odvalue,newvValue)){
                        System.out.println("Old value changed from " + odvalue);
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ExecutorService service = Executors.newCachedThreadPool();

        for(int i=0;i<N_ELEMENTS;i++){
            for(int j=0;j<N_GENES;j++){
                GRID[i][j] = new AtomicInteger(random.nextInt(1000));
            }
        }

        for (int i=0;i<N_EVOLVERS;i++){
            service.execute(new Evolver());
        }

        TimeUnit.SECONDS.sleep(5);

        service.shutdownNow();
    }
}

ReadWriteLock

允许多个任务同时访问数据结构,只要没有写入操作就行
一旦有写入操作,数据结构就会被上锁,同时也无法被读取,直到这个锁被释放为止