[ThreadLocal] Ejemplos y escenarios de uso de ThreadLocal

ThreadLocal es una medida importante para el cierre de subprocesos, y DateTimeContextHolder y RequestContextHolder en Spring también son útiles.

Escenarios de uso de ThreadLocal

Escenario 1: Aislamiento de objetos: el hilo necesita un objeto exclusivo (como SimpleDateFormat)

Los subprocesos comparten exclusivamente una clase de herramienta de objeto, como Random y DateFormat, generalmente por razones de seguridad y eficiencia de subprocesos.

Para el escenario de objetos exclusivos de subprocesos, el método principal es anular el método innitialValue ().

public class RrightWaySimpleDateFormater {
    
    
    public static ExecutorService threadPool = Executors.newFixedThreadPool(10);
    /**
     * 定义ThreadLocal变量--JDK8实现形式
     */
    private static final ThreadLocal<SimpleDateFormat> dateThreadSafe = ThreadLocal.withInitial(
        () -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
   );

    public static void main(String[] args) throws InterruptedException {
    
    
        for (int i = 0; i < 1000; i++) {
    
    
            int finalI = i;
            threadPool.submit(() -> {
    
    
                System.out.println(new RrightWaySimpleDateFormater().date(finalI));
            });
        }
        threadPool.shutdown();
    }

    public String date(int seconds) {
    
    
        return dateThreadSafe.get().format(new Date(1000 * seconds));
    }
}

JDK7 y formularios de implementación anteriores

private static final ThreadLocal<SimpleDateFormat> dateThreadSafe2 = new ThreadLocal<SimpleDateFormat>() {
    
    
     @Override
     protected SimpleDateFormat initialValue() {
    
    
         return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
     }
};

Cabe señalar que ThreadLocal generalmente no es adecuado para grupos de subprocesos.

Ali java manual:
[Obligatorio] SimpleDateFormat es una clase insegura para subprocesos y, por lo general, no debe definirse como una variable estática. Si está definido como estático, debe estar bloqueado o utilizar la clase de herramienta DateUtils. También se recomienda el tratamiento anterior.
JDK8 recomienda usar DateTimeFormatter en lugar de SimpleDateFormat, Instant en lugar de Date y LocalDateTime en lugar de Calendar.

Escenario 2: transferencia de objetos

Los subprocesos necesitan guardar variables globales para que se puedan usar diferentes métodos directamente, sin la necesidad de pasar datos capa por capa como parámetros.

ThreadLocal se puede utilizar para guardar cierta información comercial, como información de autoridad de usuario, nombre de usuario, ID de usuario, número de teléfono móvil, etc. La información comercial es la misma en el mismo hilo, pero el contenido en diferentes hilos es diferente. El énfasis está en compartir entre diferentes métodos dentro de la misma solicitud (dentro del mismo hilo).

El mapa también puede almacenar la información comercial anterior. Cuando varios subprocesos funcionan al mismo tiempo, se debe garantizar la seguridad de los subprocesos. Por ejemplo, el uso de una variable estática ConcurrentHashMap, el uso del ID de subproceso como clave y el almacenamiento de los datos comerciales como Valor, puede lograr el aislamiento entre subprocesos, pero aún tiene un impacto en el rendimiento.

public class RightWayThreadLocalUse {
    
    
    public static void main(String[] args) {
    
    
        new ServiceImpl1().service(new UserInfo("lzp", "1234567890"));
    }
}

/**
 * 接收数据
 */
class ServiceImpl1 {
    
    
    public void service(UserInfo userInfo) {
    
    
        UserInfoHolder.holder.set(userInfo);
        new ServiceImpl2().service();
    }
}

/**
 * 处理数据1
 */
class ServiceImpl2 {
    
    
    public void service() {
    
    
        System.out.println("客户名:" + UserInfoHolder.holder.get().cltNam);
        new ServiceImpl3().service();
    }
}

/**
 * 处理数据2
 */
class ServiceImpl3 {
    
    
    public void service() {
    
    
        System.out.println("客户号:" + UserInfoHolder.holder.get().cltNbr);
        // 此时使用完ThreadLocal,回收该ThreadLocal
        UserInfoHolder.holder.remove();
    }
}

class UserInfoHolder {
    
    
    public static ThreadLocal<UserInfo> holder = new ThreadLocal<>();
}

class UserInfo {
    
    
    String cltNam;
    String cltNbr;

    public UserInfo(String cltNam, String cltNbr) {
    
    
        this.cltNam = cltNam;
        this.cltNbr = cltNbr;
    }
}

Ventajas de ThreadLocal

(1) La variable ThreadLocal es privada para el subproceso, por lo que el subproceso es seguro y no necesita bloquearse, por lo que no hay bloqueo y se mejora la eficiencia de ejecución.
(2) Utilice la memoria de forma eficiente y ahorre gastos generales. Para el escenario de uso del grupo de subprocesos, solo es necesario que cada subproceso de trabajo tenga una instancia ThreadLocal del objeto.
(3) Para el escenario de la cadena de llamadas, evite la transmisión repetida de objetos, utilizados para almacenar información comercial, y logre el desacoplamiento del código.

Supongo que te gusta

Origin blog.csdn.net/LIZHONGPING00/article/details/105211631
Recomendado
Clasificación