02-JUC--ThreadLocal

ThreadLocal的用途

在这里插入图片描述

场景1:每个线程都需要一个独享的对象

在这里插入图片描述
在这里插入图片描述

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);
    }
}

引出问题
在这里插入图片描述

当所有对象都共用一个simpledateformat对象的时候,就会发生线程安全问题。
使用静态对象在多线程环境下是不行的。


/**
 * @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);
    }
}

使用synchronized关键字也可以解决多线程下共享静态对象的线程安全问题


/**
 * @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;
    }
}

使用ThreadLocal工具类来解决此类共享对象的任务


/**
 * @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");
                }
            };
}

场景2:线程内方法共享信息问题

在这里插入图片描述

在这里插入图片描述
解决思路
在这里插入图片描述

在这里插入图片描述


/**
 * @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;}
}

ThreadLocal的两个作用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ThreadLocal详解

源码分析

每一个Thread都有一个ThreadLocalMap,这个map里面存储了很多ThreadLocal
在这里插入图片描述

在这里插入图片描述

ThreadLocal主要方法介绍

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

ThreadLocalMap

在这里插入图片描述

使用Thread要注意的地方

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41729287/article/details/113831132
JUC
今日推荐