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