02-JUC - ThreadLocal

El propósito de ThreadLocal

Inserte la descripción de la imagen aquí

Escenario 1: cada hilo necesita un objeto exclusivo

Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí

public class ThreadLocalNormalUsage00 {
    
    

    public static void main(String[] args) {
    
    
        new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                String date = new ThreadLocalNormalUsage00().date(10);
                System.out.println(date);
            }
        }).start();
        new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                String date = new ThreadLocalNormalUsage00().date(1007);
                System.out.println(date);
            }
        }).start();
    }

    public String date(int seconds){
    
    
        //参数的单位是毫秒,从1970.1.1 00:00:00 GMT计时
        Date date  = new Date(1000 * seconds);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        return simpleDateFormat.format(date);
    }
}

Haz la pregunta
Inserte la descripción de la imagen aquí

Cuando todos los objetos comparten un objeto de formato de fecha simple, se producen problemas de seguridad de subprocesos.
El uso de objetos estáticos no es factible en un entorno de subprocesos múltiples.


/**
 * @Classname ThreadLocalNormalUsage00
 * @Description 1000个打印日期的任务,用线程池执行;此时线程共享一个静态对象会发生线程安全问题。
 * @Date 2021/2/17 9:24
 * @Created by YoungLiu
 */
public class ThreadLocalNormalUsage03 {
    
    

    public static ExecutorService threadPool = Executors.newFixedThreadPool(10);
    static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

    public static void main(String[] args) {
    
    
        for (int i = 0; i < 1000; i++) {
    
    
            int finalI = i;
            Runnable runnable = new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    String date = new ThreadLocalNormalUsage03().date(finalI);
                    System.out.println(Thread.currentThread().getName() + date);
                }
            };
            threadPool.submit(runnable);
        }
        threadPool.shutdown();
    }

    public String date(int seconds) {
    
    
        //参数的单位是毫秒,从1970.1.1 00:00:00 GMT计时
        Date date = new Date(1000 * seconds);
        return simpleDateFormat.format(date);
    }
}

El uso de la palabra clave sincronizada también puede resolver el problema de seguridad de los subprocesos al compartir objetos estáticos en varios subprocesos.


/**
 * @Classname ThreadLocalNormalUsage00
 * @Description  加锁来解决线程安全问题
 * @Date 2021/2/17 9:24
 * @Created by YoungLiu
 */
public class ThreadLocalNormalUsage04 {
    
    

    public static ExecutorService threadPool = Executors.newFixedThreadPool(10);
    static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

    public static void main(String[] args) {
    
    
        for (int i = 0; i < 1000; i++) {
    
    
            int finalI = i;
            Runnable runnable = new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    String date = new ThreadLocalNormalUsage04().date(finalI);
                    System.out.println(Thread.currentThread().getName() + date);
                }
            };
            threadPool.submit(runnable);
        }
        threadPool.shutdown();
    }

    public String date(int seconds) {
    
    
        //参数的单位是毫秒,从1970.1.1 00:00:00 GMT计时
        Date date = new Date(1000 * seconds);
        String format;
        synchronized (ThreadLocalNormalUsage04.class){
    
    
             format = simpleDateFormat.format(date);
        }
        return format;
    }
}

Utilice la clase de herramienta ThreadLocal para resolver la tarea de dichos objetos compartidos


/**
 * @Classname ThreadLocalNormalUsage00
 * @Description 利用ThreadLocal,给每个线程分配自己的dateFormat对象,保证了线程安全,高效利用内存。
 * @Date 2021/2/17 9:24
 * @Created by YoungLiu
 */
public class ThreadLocalNormalUsage05 {
    
    

    public static ExecutorService threadPool = Executors.newFixedThreadPool(10);

    public static void main(String[] args) {
    
    
        for (int i = 0; i < 1000; i++) {
    
    
            int finalI = i;
            Runnable runnable = new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    String date = new ThreadLocalNormalUsage05().date(10000 + finalI);
                    System.out.println(Thread.currentThread().getName() + date);
                }
            };
            threadPool.submit(runnable);
        }
        threadPool.shutdown();
    }

    public String date(int seconds) {
    
    
        //参数的单位是毫秒,从1970.1.1 00:00:00 GMT计时
        Date date = new Date(1000 * seconds);
        //这个里的get方法返回的是  initialValue()的返回对象
        SimpleDateFormat simpleDateFormat = ThreadSafeFormatter.dateFormatThreadLocal.get();
        return simpleDateFormat.format(date);
    }
}

class ThreadSafeFormatter {
    
    
    public static ThreadLocal<SimpleDateFormat> dateFormatThreadLocal =
            new ThreadLocal<SimpleDateFormat>() {
    
    
                @Override
                protected SimpleDateFormat initialValue() {
    
    
                    return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
                }
            };
}

Escenario 2: problema de intercambio de información de método en subproceso

Inserte la descripción de la imagen aquí

Inserte la descripción de la imagen aquí
Soluciones
Inserte la descripción de la imagen aquí

Inserte la descripción de la imagen aquí


/**
 * @Classname ThreadLocalNormalUsage06
 * @Description  演示ThreadLocal用法2:避免传递参数的麻烦
 * @Date 2021/2/17 10:19
 * @Created by YoungLiu
 */
public class ThreadLocalNormalUsage06 {
    
    
    public static void main(String[] args) {
    
    
        Service1 service1 = new Service1();
        service1.process();
    }
}

class Service1{
    
    
    public void process(){
    
    
        User user = new User("超哥");
        UserContextHolder.holder.set(user);
        new Service2().process();
    }
}
class Service2{
    
    
    public void process(){
    
    
        User user = UserContextHolder.holder.get();
        System.out.println("Service2拿到用户名"+user.name);
        new Service3().process();
    }
}
class Service3{
    
    
    public void process(){
    
    
        User user = UserContextHolder.holder.get();
        System.out.println("Service3拿到用户名:"+user.name);
    }
}

class UserContextHolder{
    
    
    public static ThreadLocal<User> holder = new ThreadLocal<>();
}

class User{
    
    
    String name;
    public User(String name){
    
    this.name=name;}
}

Dos funciones de ThreadLocal

Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí

ThreadLocal detallado

Análisis de código fuente

Cada hilo tiene un ThreadLocalMap, que almacena una gran cantidad de ThreadLocal
Inserte la descripción de la imagen aquí

Inserte la descripción de la imagen aquí

Introducción a los principales métodos de ThreadLocal

Inserte la descripción de la imagen aquí

Inserte la descripción de la imagen aquí

Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí

Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí

ThreadLocalMap

Inserte la descripción de la imagen aquí

Puntos a tener en cuenta al usar Thread

Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_41729287/article/details/113831132
Recomendado
Clasificación