zoukankan      html  css  js  c++  java
  • 多线程--ThreadLocal类

    一.ThreadLocal类简介
    --此类是在整个开发过程中至关重要的类,他主要是在开发过程中解决了核心资源和多线程并发访问的处理情况
    --在真正去了解ThreadLocal类作用的时候,我们可以先编写一个简单的程序做一个前期的分析
    --范例:现在定义这样的一个结构

     1 package 多线程.threadlocal类;
     2 
     3 /**
     4  * @author : S K Y
     5  * @version :0.0.1
     6  */
     7 class Channel {      //消息的发送通道
     8     private static Message message;
     9 
    10     public static void setMessage(Message message) {
    11         Channel.message = message;
    12     }
    13 
    14     public static void send() {      //发送消息
    15         System.out.println("消息发送: " + message.getInfo());
    16     }
    17 }
    18 
    19 class Message {      //要发送的消息体
    20     private String info;
    21 
    22     public String getInfo() {
    23         return info;
    24     }
    25 
    26     public void setInfo(String info) {
    27         this.info = info;
    28     }
    29 }
    30 
    31 public class MyThreadLocal {
    32     public static void main(String[] args) {
    33         Message message = new Message();        //实例化消息主体对象
    34         message.setInfo("test");        //设置要发送的消息内容
    35         Channel.setMessage(message);
    36         Channel.send();     //发送消息
    37     }
    38 }

     --当前的程序实现是单线程的,如果在多线程的状态下它能否实现完全一致的操作效果呢,启动三个线程进行测试

     1 class Channel {      //消息的发送通道
     2     private static Message message;
     3 
     4     public static void setMessage(Message message) {
     5         Channel.message = message;
     6     }
     7 
     8     public static void send() {      //发送消息
     9         System.out.println(Thread.currentThread().getName() + " 消息发送: " + message.getInfo());
    10     }
    11 }
    12 public class MyThreadLocal {
    13     public static void main(String[] args) {
    14         new Thread(() -> {
    15             Message message = new Message();        //实例化消息主体对象
    16             message.setInfo("第一个线程的消息信息");        //设置要发送的消息内容
    17             Channel.setMessage(message);
    18             Channel.send();     //发送消息
    19         },"消息发送者A").start();
    20         new Thread(() -> {
    21             Message message = new Message();        //实例化消息主体对象
    22             message.setInfo("第二个线程的消息信息");        //设置要发送的消息内容
    23             Channel.setMessage(message);
    24             Channel.send();     //发送消息
    25         },"消息发送者B").start();
    26         new Thread(() -> {
    27             Message message = new Message();        //实例化消息主体对象
    28             message.setInfo("第三个线程的消息信息");        //设置要发送的消息内容
    29             Channel.setMessage(message);
    30             Channel.send();     //发送消息
    31         },"消息发送者C").start();
    32     }
    33 }

    --理论上消息的发送应该是各自发送各自的消息内容,但是我们观察程序运行结果

    消息发送者A 消息发送: 第二个线程的消息信息
    消息发送者C 消息发送: 第三个线程的消息信息
    消息发送者B 消息发送: 第二个线程的消息信息
    
    Process finished with exit code 0

    --这个时候消息的处理产生了影响,在Channel类的实现中,是依赖使用static Message message来完成的,在线程A设置完对象信息但还未发送时,线程B就进行了对象了覆盖,这样就将会造成消息内容的覆盖问题,这个过程就被称之为不同步,面对这样的情况,解决同步问题在Channel核心结构不改变的情况下需要考虑每个线程的运行情况,对于Channel类而言除了要保留有发送的消息之外,还应该多存放有一个每一个线程的标记(当前线程的使用标记),那么这个时候就可以通过ThreadLocal类来存放数据
    --在ThreadLocal类中定义有如下方法
    构造方法:public ThreadLocal()

    T get()
    返回当前线程的此线程局部变量的副本中的值。
    protected T initialValue()
    返回此线程局部变量的当前线程的“初始值”。
    void remove()
    删除此线程局部变量的当前线程的值。
    void set(T value)
    将当前线程的此线程局部变量的副本设置为指定的值。
    static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier)
    创建线程局部变量。
    --范例:使用ThreadLocal来存放数据变量实现数据的同步

     1 package 多线程.threadlocal类;
     2 
     3 /**
     4  * @author : S K Y
     5  * @version :0.0.1
     6  */
     7 class Channel {      //消息的发送通道
     8     //私有静态常量
     9     private static final ThreadLocal<Message> THREAD_LOCAL = new ThreadLocal<>();
    10 
    11     public static void setMessage(Message message) {
    12         THREAD_LOCAL.set(message);
    13     }
    14 
    15     public static void send() {      //发送消息
    16         System.out.println(Thread.currentThread().getName() + " 消息发送: " + THREAD_LOCAL.get().getInfo());
    17     }
    18 }
    19 
    20 class Message {      //要发送的消息体
    21     private String info;
    22 
    23     public String getInfo() {
    24         return info;
    25     }
    26 
    27     public void setInfo(String info) {
    28         this.info = info;
    29     }
    30 }
    31 
    32 public class MyThreadLocal {
    33     public static void main(String[] args) {
    34         new Thread(() -> {
    35             Message message = new Message();        //实例化消息主体对象
    36             message.setInfo("第一个线程的消息信息");        //设置要发送的消息内容
    37             Channel.setMessage(message);
    38             Channel.send();     //发送消息
    39         },"消息发送者A").start();
    40         new Thread(() -> {
    41             Message message = new Message();        //实例化消息主体对象
    42             message.setInfo("第二个线程的消息信息");        //设置要发送的消息内容
    43             Channel.setMessage(message);
    44             Channel.send();     //发送消息
    45         },"消息发送者B").start();
    46         new Thread(() -> {
    47             Message message = new Message();        //实例化消息主体对象
    48             message.setInfo("第三个线程的消息信息");        //设置要发送的消息内容
    49             Channel.setMessage(message);
    50             Channel.send();     //发送消息
    51         },"消息发送者C").start();
    52     }
    53 }

     --运行结果

    消息发送者A 消息发送: 第一个线程的消息信息
    消息发送者C 消息发送: 第三个线程的消息信息
    消息发送者B 消息发送: 第二个线程的消息信息
    
    Process finished with exit code 0
  • 相关阅读:
    Spring Boot----SpringData
    Spring Boot----整合MyBatis
    Spring Boot----整合jdbc和整合Durid数据源
    Spring Boot----嵌入式servlet和外置servlet使用
    大数据 CDH 5.8 安装
    Java 单例模式
    python 常用方法
    使用wepy开发微信小程序商城第三篇:购物车(布局篇)
    js时间戳转化成日期格式
    使用wepy开发微信小程序商城第二篇:路由配置和页面结构
  • 原文地址:https://www.cnblogs.com/skykuqi/p/11379506.html
Copyright © 2011-2022 走看看