Entrevistador: ¿Java tiene un conjunto seguro para subprocesos?

 
  
 
  
 
  
 
  
您好,我是路人,更多优质文章见个人博客:http://itsoku.com

En un entorno de subprocesos múltiples, utilice una colección segura para subprocesos, por ejemplo, ConcurrentHashMap es un HashMap seguro para subprocesos y CopyOnWriteArrayList es un ArrayList seguro para subprocesos. Entonces, ¿cuál es la colección segura para subprocesos correspondiente a HashSet? ¿Java proporciona una implementación predeterminada?

En el paquete concurrente de Java, encontré CopyOnWriteArraySet, entonces, ¿es seguro para subprocesos? A continuación se muestra el código de prueba.

public static void main(String[] args) {
        Set<String> set = new CopyOnWriteArraySet<>();
        ExecutorService service = Executors.newFixedThreadPool(12);
        int times = 10000;
        AtomicInteger flag = new AtomicInteger(0);
        for(int i = 0; i < times; i ++){
            service.execute(()->{
                set.add("a" + flag.getAndAdd(1));
            });
        }
        service.shutdown();
        try {
            service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println(set.size());
    }

Después de múltiples ejecuciones, el resultado es 10000. Se puede explicar que CopyOnWriteArraySet es un conjunto seguro para subprocesos.

Entonces, ¿cómo garantiza CopyOnWriteArraySet la seguridad de los subprocesos al escribir? El siguiente es el código fuente agregado de CopyOnWriteArraySet.

public boolean add(E e) {
        return al.addIfAbsent(e);
    }
    public boolean addIfAbsent(E e) {
        Object[] snapshot = getArray();
        return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
            addIfAbsent(e, snapshot);
    }
    private static int indexOf(Object o, Object[] elements,
                               int index, int fence) {
        if (o == null) {
            for (int i = index; i < fence; i++)
                if (elements[i] == null)
                    return i;
        } else {
            for (int i = index; i < fence; i++)
                if (o.equals(elements[i]))
                    return i;
        }
        return -1;
    }
    private boolean addIfAbsent(E e, Object[] snapshot) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] current = getArray();
            int len = current.length;
            if (snapshot != current) {
                // Optimize for lost race to another addXXX operation
                int common = Math.min(snapshot.length, len);
                for (int i = 0; i < common; i++)
                    if (current[i] != snapshot[i] && eq(e, current[i]))
                        return false;
                if (indexOf(e, current, common, len) >= 0)
                        return false;
            }
            Object[] newElements = Arrays.copyOf(current, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

Se puede ver en el código fuente que la capa inferior de CopyOnWriteArraySet se implementa mediante la estructura de datos CopyOnWriteArrayList. Al agregar elementos, se utilizan bloqueos reentrantes para lograr la seguridad de los subprocesos.

446fa13b40ee67551da5480340a041f7.png

↓  Haz clic para leer el texto original e ir directamente a mi blog personal

99e8de64876d917f9f480bd6732cf7f5.jpeg Estás viendo

Supongo que te gusta

Origin blog.csdn.net/likun557/article/details/131671856
Recomendado
Clasificación