¿Es necesario utilizar AtomicInteger en un ThreadFactory?

caballeros:

Creo que es necesario utilizar AtomicIntegeren el ThreadFactory pero cuando estoy tratando de demostrar a mí mismo, no he logrado duro.

    new ThreadFactory() {

        private int threadId = 0;   <---- AtomicInteger preferred

        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            t.setDaemon(true);
            t.setName("my-thread-" + (threadId++));   <--- dangerous code
            return t;
        }
    }

Si varias peticiones vienen, la fábrica de hilos va a generar hilos para manejarlos y durante la generación, no podría haber un espacio en el que una condición de carrera podría colarse.

Probé con el siguiente código para demostrar mi teoría, pero que no está sucediendo en absoluto con 2_000 hilos de núcleo.

@Slf4j
public class ThreadFactoryTest {

    private ConcurrentHashMap<String, Thread> threadIdThreadMap = new ConcurrentHashMap<>();
    private ThreadPoolExecutor myExecutor = new ThreadPoolExecutor(2000, 2000, 30, TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(100000), new ThreadFactory() {

        private int threadId = 0;

        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            t.setDaemon(true);
            t.setName("my-thread-" + (threadId++));
            if (threadIdThreadMap.contains(t.getName())) {
                log.error("already existed");
                System.err.println(myExecutor);
                myExecutor.shutdownNow();
            } else threadIdThreadMap.put(t.getName(), t);
            return t;
        }
    }, new ThreadPoolExecutor.AbortPolicy());

    @Test
    public void testThreadFactory() throws Exception {
        for (int i = 0; i < 100; ++i) {
            new Thread(() -> runOneHundredJobs()).start();
        }
        Thread.sleep(1000000);
        myExecutor.shutdown();
        myExecutor.awaitTermination(100, TimeUnit.MINUTES);
    }

    private void runOneHundredJobs() {
        log.info("{} starting to submit tasks", Thread.currentThread().getName());
        for (int i = 0; i < 100; ++i) {
            myExecutor.execute(() -> {
                while (100 < System.currentTimeMillis()) {
                    try {
                        Thread.sleep(1000);
                        if (Math.random() > 0.99) break;
                        System.out.println(Thread.currentThread().getName());
                        System.out.println(myExecutor);
                    } catch (Exception e) {

                    }
                }
            } );
        }
    }
}

Se parece a una pregunta estúpida ya que siempre se que " es difícil crear la brecha para una condición de carrera multi-hilo ".

Cualquier ayuda / pista se apreciará;)

ACTUALIZAR

Realmente gracias por la ayuda en el camino, y @StephenC @Slaw. Siento que no he entendido bien algunos puntos allí; (

Por lo tanto newThreadse deben implementar en un thread-safe manera y luego en mi caso, la AtomicIntegerse requiere. Y yo quiero tener una cita de StephenC:

La imposibilidad de demostrar una condición de carrera no significa que no existe.

Stephen C:

¿Es necesario utilizar AtomicInteger en un ThreadFactory?

Dependerá de cómo se utiliza el objeto de fábrica.

  • Si proporciona un objeto de fábrica diferente a cada instancia de ThreadPoolExecutorentonces los requisitos (reales) de simultaneidad en la fábrica dependerá de cómo el ejecutor utiliza. En ausencia de declaraciones en las javadocs, que tendría que examinar el código fuente. No he comprobado, pero sospecho que la expansión del grupo de subprocesos (incluyendo la llamada a newThread) ocurrir dentro de un mutex. Si mi sospecha es correcta, entonces este caso de uso no requiere el objeto de fábrica para ser seguro para subprocesos.

    ACTUALIZACIÓN - Ahora he comprobado, y mi sospecha era incorrecta (para Java 8 y 12). La newThreadllamada se realiza cuando se crea un nuevo Workerobjeto, y que no se realiza mientras se mantiene un mutex. Por lo tanto, el newThreadmétodo tiene que ser seguro para subprocesos en este contexto también.

  • Si un objeto de fábrica es compartida con otras cosas (por ejemplo, otro ejecutor) a continuación, estás en lo correcto: sus newThreadnecesidades método a ser seguro para subprocesos.


No he mirado en su código para tratar de mostrar las condiciones de carrera, pero en mi opinión, eso no es la mejor manera de ir sobre esto. inspección de código y el razonamiento es una mejor manera. La imposibilidad de demostrar una condición de carrera no significa que no existe.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=336398&siteId=1
Recomendado
Clasificación