Java ThreadLocal 应用,向两个Socket地址发相同的指令

Java ThreadLocal 应用,向两个Socket地址发相同的指令。

例:向docker两个服务器的5856端口发相同指令。

为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突

package cn.wxtong.rent.common;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

class SocketMessage
{
    private final ThreadLocal<String> t = new ThreadLocal<>();

    String host;
    public String message;
    public int port;

    public SocketMessage(String message){
        this.message = message;
    }
    public String getMessage() {
        return t.get();
    }
    public void setMessage(String message) {
        this.t.set(message);
    }

    @Override
    public String toString() {
        return "SocketMessage{" +
                "t=" + t +
                ", host='" + host + '\'' +
                ", message='" + message + '\'' +
                ", port=" + port +
                '}';
    }

    /** 关闭充电指令 */
    public static final String CMD_CHARGE_OFF = "DD5AE1020001FF1C77";
    /** 关闭放电指令* */
    public static final String CMD_DISCHARGE_OFF = "DD5AE1020002FF1B77";
    /** 全部打开指令* */
    public static final String CMD_OPEN_ALL = "DD5AE1020000FF1D77";
    /** 全部关闭指令 */
    public static final String CMD_CLOSE_ALL = "DD5AE1020003FF1A77";
    //
    public static final String CMD_73 = "DD5A07085833383558333835FE0177";//设置验证
    public static final String CMD_74 = "DD5A060458333835FEFE77";//手动验证
    public static final String CMD_75 = "787811D006003C003CDD5A060458333835FEFE770D0A";//保存06储存器自动验证
    public static final String CMD_98 = "DD5A0E028118FF5777";//
    //
    //换电柜
    public static final String OPEN_DOOR = "";//保存06储存器自动验证

}

/**
 * Java Socket Client Util
 * @Address 120.76.42.40
 * @Port 5856
 * @Msg *wxt*2201000008*78780249010d0a
 */

//Java ThreadLocal 实例 向两个Socket地址发相同的指令
public class SocketUtils implements Runnable
{
    private final SocketMessage socketMessage;

    public static final String HOST135 = "192.168.6.135";
    public static final String HOST40 = "192.168.6.40";
    public static String[] hosts = { HOST135, HOST40 };
    public int port = 5856;

    /** 关闭充电指令 */
    public static final String CMD_CHARGE_OFF = "DD5AE1020001FF1C77";
    /** 全部打开指令* */
    public static final String CMD_OPEN_ALL = "DD5AE1020000FF1D77";

    //
    public SocketUtils(SocketMessage socketMessage){
        this.socketMessage = socketMessage;
    }
    //main test
    public static void main(String[] args)
    {
        SocketUtils.sendMessage("2201000001", SocketUtils.CMD_OPEN_ALL);
        SocketUtils.sendMessage("2201000002", SocketUtils.CMD_CHARGE_OFF );
    }
	
    public static void sendMessage(String devId, String instruction){
        String msg = "*test*" + devId + "*" + instruction;
        
        //为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突
        for(int i = 0; i< SocketUtils.hosts.length; i++)
        {
            SocketMessage message = new SocketMessage(msg);
            message.host = SocketUtils.hosts[i];
            message.port = 5856;
            //
            SocketUtils socket = new SocketUtils(message);
            new Thread(socket).start();
        }
    }

    @Override
    public void run()
    {
        socketMessage.setMessage(socketMessage.message);
        this.send( socketMessage.host, socketMessage.port, socketMessage.message);
		//
        System.out.println(Thread.currentThread() +" --- send" + socketMessage.message);

    }

    public void send(String host, int port, String msg)
    {
        OutputStream outputStream = null;
        InputStream inputStream = null;
        try{
            Socket socket = new Socket(host, port);
            if (socket.isConnected())
            {
                System.out.println("socket client connect success:" + socket.getRemoteSocketAddress() +" send msg:" + msg);
                outputStream = socket.getOutputStream();
                outputStream.write(msg.getBytes());
                socket.shutdownOutput();
                //读取
                inputStream = socket.getInputStream();
                byte[] bytes = new byte[1024];
                int len = 0;
                while((len = inputStream.read(bytes)) > 0)
                {
                    outputStream.write(bytes, 0, len);
                    System.out.println("read socket return msg:" + new String(bytes));
                }
            }
        }catch(Exception e) {
            System.out.println("send socket cmd exception, msg:" + socketMessage + "\n" + e.getMessage());
        }finally {
            try{
                if(outputStream != null) outputStream.close();
                if(inputStream != null) inputStream.close();
            }catch (Exception e){
                System.out.println("socket client close exception");
            }
        }
    }

}

资料来源

本文实例讲述了Java ThreadLocal类应用。分享给大家供大家参考,具体如下:
https://www.jb51.net/article/170442.htm

ThreadLocal,是Thread Local Variable(线程局部变量)的意思,也许将它命名为ThreadLocalVar更加合适。

线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有该变量。

ThreadLocal类的用法非常简单,它只提供了如下三个public方法:

T get():返回此线程局部变量中当前线程副本中的值。
void remove():删除此线程局部变量中当前线程的值。
void set(T value):设置此线程局部变量中当前线程副本中的值。

class Account
{
   /* 定义一个ThreadLocal类型的变量,该变量将是一个线程局部变量
   每个线程都会保留该变量的一个副本 */
   private ThreadLocal<String> name = new ThreadLocal<>();
   // 定义一个初始化name成员变量的构造器
   public Account(String str)
   {
      this.name.set(str);
      // 下面代码用于访问当前线程的name副本的值
      System.out.println("---" + this.name.get());
   }
   // name的setter和getter方法
   public String getName()
   {
      return name.get();
   }
   public void setName(String str)
   {
      this.name.set(str);
   }
}
class MyTest extends Thread
{
   // 定义一个Account类型的成员变量
   private Account account;
   public MyTest(Account account, String name)
   {
      super(name);
      this.account = account;
   }
   public void run()
   {
      // 循环10次
      for (int i = 0 ; i < 10 ; i++)
      {
        // 当i == 6时输出将账户名替换成当前线程名
        if (i == 6)
        {
           account.setName(getName());
        }
        // 输出同一个账户的账户名和循环变量
        System.out.println(account.getName()
           + " 账户的i值:" + i);
      }
   }
}
public class ThreadLocalTest
{
   public static void main(String[] args)
   {
      // 启动两条线程,两条线程共享同一个Account,
      // 主线程中有一个Account的name,线程甲和线程乙中也各有一个Account的name,三者互不干扰
      Account at = new Account("初始名");
      /*
      虽然两条线程共享同一个账户,即只有一个账户名
      但由于账户名是ThreadLocal类型的,所以每条线程
      都完全拥有各自的账户名副本,所以从i == 6之后,将看到两条
      线程访问同一个账户时看到不同的账户名。
      */
      new MyTest(at , "线程甲").start();
      new MyTest(at , "线程乙").start ();
   }
}

参考资料

ThreadLocal 是什么?有哪些使用场景?
https://blog.csdn.net/meism5/article/details/90413860

ThreadLocal类应用实战案例分析 https://www.jb51.net/article/170442.htm

实战java高并发程序设计之ThreadLocal源码分析
https://blog.csdn.net/nobody_1/article/details/83318040

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值