Java 多线程之间共享数据

网友投稿 235 2022-09-19


Java 多线程之间共享数据

目录1、线程范围的共享变量2、使用Map实现线程范围内数据的共享3、ThreadLocal实现线程范围内数据的共享4、优化5、实例

1、线程范围的共享变量

多个业务模块针对同一个static变量的操作 要保证在不同线程中 各模块操作的是自身对应的变量对象

public class ThreadScopeSharaData {

private static int data = 0 ;

public static void main(String[] args) {

for(int i = 0 ;i<2 ;i++){

new Thread(new Runnable(){

@Override

public void run() {

data = new Random().nextInt();

System.out.println(Thread.currentThread().getName()+ " put random data:"+data);

new A().get() ;

new B().get() ;

}

}).start() ;

}

}

static class A http://{

public int get(){

System.out.println("A from " + Thread.currentThread().getName()

+ " get data :" + data);

return data ;

}

}

static class B{

public int get(){

System.out.println("B from " + Thread.currentThread().getName()

+ " get data :" + data);

return data ;

}

}

}

模块A ,B都需要访问static的变量data 在线程0中会随机生成一个data值 假设为10 那么此时模块A和模块B在线程0中得到的data的值为10 ;在线程1中 假设会为data赋值为20 那么在当前线程下

模块A和模块B得到data的值应该为20

看程序执行的结果:

Thread-0 put random data:-2009009251

Thread-1 put random data:-2009009251

A from Thread-0 get data :-2009009251

A from Thread-1 get data :-2009009251

B from Thread-0 get data :-2009009251

B from Thread-1 get data :-2009009251

Thread-0 put random data:-2045829602

Thread-1 put random data:-1842611697

A from Thread-0 get data :-1842611697

A from Thread-1 get data :-1842611697

B from Thread-0 get data :-1842611697

B from Thread-1 get data :-1842611697

会出现两种情况:

1.由于线程执行速度,新的随机值将就的随机值覆盖 data 值一样

2.data 值不一样,但 A、B线程都

2、使用Map实现线程范围内数据的共享

可是将data数据和当前允许的线程绑定在一块,在模块A和模块B去获取数据data的时候 是通过当前所属的线程去取得data的结果就行了。

声明一个Map集合 集合的Key为Thread 存储当前所属线程 Value 保存data的值,

代码如下:

public class ThreadScopeSharaData {

private static Map threadData = new HashMap<>();

public static void main(String[] args) {

for (int i = 0; i < 2; i++) {

new Thread(new Runnable() {

@Override

public void run() {

int data = new Random().nextInt();

System.out.println(Thread.currentThread().getName() + " put random data:" + data);

threadData.put(Thread.currentThread(), data);

new A().get();

new B().get();

}

}).start();

}

}

static class A {

public void get() {

int data = threadData.get(Thread.currentThread());

System.out.println("A from " + Thread.currentThread().getName() + " get data:" + data);

}

}

static class B {

public void get() {

int data = threadData.get(Thread.currentThread());

System.out.println("B from " + Thread.currentThread().getName() + " get data:" + data);

}

}

}

Thread-0 put random data:-123490895

Thread-1 put random data:-1060992440

A from Thread-0 get data:-123490895

A from Thread-1 get data:-1060992440

B from Thread-0 get data:-123490895

B from Thread-1 get data:-1060992440

3、ThreadLocal实现线程范围内数据的共享

(1)订单处理包含一系列操作:减少库存量、增加一条流水台账、修改总账,这几个操作要在同一个事务中完成,通常也即同一个线程中进行处理,如果累加公司应收款的操作失败了,则应该把前面的操作回滚,否则,提交所有操作,这要求这些操作使用相同的数据库连接对象,而这些操作的代码分别位于不同的模块类中。

(2)银行转账包含一系列操作: 把转出帐户的余额减少,把转入帐户的余额增加,这两个操作要在同一个事务中完成,它们必须使用相同的数据库连接对象,转入和转出操作的代码分别是两个不同的帐户对象的方法。

(3)例如Strut2的ActionContext,同一段代码被不同的线程调用运行时,该代码操作的数据是每个线程各自的状态和数据,对于不同的线程来说,getContext方法拿到的对象都不相同,对同一个线程来说,不管调用getContext方法多少次和在哪个模块中getContext方法,拿到的都是同一个。

(4)实验案例:定义一个全局共享的ThreadLocal变量,然后启动多个线程向该ThreadLocal变量中存储一个随机值,接着各个线程调用另外其他多个类的方法,这多个类的方法中读取这个ThreadLocal变量的值,就可以看到多个类在同一个线程中共享同一份数据。

(5)实现对ThreadLocal变量的封装,让外界不要直接操作ThreadLocal变量。

对基本类型的数据的封装,这种应用相对很少见。

对对象类型的数据的封装,比较常见,即让某个类针对不同线程分别创建一个独立的实例对象。

public class ThreadLocalTest {

private static ThreadLocal threadLocal = new ThreadLocal<>();

public static void main(String[] args) {

for (int i = 0; i < 2; i++) {

new Thread(new Runnable() {

@Override

public void run() {

int data = new Random().nextInt();

System.out.println(Thread.currentThread().getName() + " put random data:" + data);

threadLocal.set(data);

new A().get();

new B().get();

}

}).start();

}

}

static class A {

public void get() {

int data = threadLocal.get();

System.out.println("A from " + Thread.currentThread().getName() + " get data:" + data);

}

}

static class B {

public void get() {

int data = threadLocal.get();

System.out.println("B from " + Thread.currentThread().getName() + " get data:" + data);

}

}

}

Thread-0 put random data:-2015900409

Thread-1 put random data:-645411160

A from Thread-0 get data:-2015900409

A from Thread-1 get data:-645411160

B from Thread-0 get data:-2015900409

B from Thread-1 get data:-645411160

4、优化

public class ThreadLocalTest {

private static ThreadLocal threadLochttp://al = new ThreadLocal<>();

//private static ThreadLocal myThreadScopeDataThreadLocal = new ThreadLocal<>();

public static void main(String[] args) {

for (int i = 0; i < 2; i++) {

new Thread(new Runnable() {

@Override

public void run() {

int data = new Random().nextInt();

System.out.println(Thread.currentThread().getName() + " put random data:" + data);

threadLocal.set(data);

// MyThreadScopeData myThreadScopeData = new MyThreadScopeData();

// myThreadScopeData.setName("name" + data);

// myThreadScopeData.setAge(data);

// myThreadScopeDataThreadLocal.set(myThreadScopeData);

//获取与当前线程绑定的实例并设置值

MyThreadScopeData.getThreadInstance().setName("name" + data);

MyThreadScopeData.getThreadInstance().setAge(data);

new A().get();

new B().get();

}

}).start();

}

}

static class A {

public void get() {

int data = threadLocal.get();

// MyThreadScopeData myData = myThreadScopeDataThreadLocal.get();

//

//

// System.out.println("A from " + Thread.currentThread().getName()

// + " getMyData: " + myData.getName() + "," + myquPuuSsbData.getAge());

MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();

System.out.println("A from " + Thread.currentThread().getName()

+ " getMyData: " + myData.getName() + "," + myData.getAge());

}

}

static class B {

public void get() {

int data = threadLocal.get();

//System.out.println("B from " + Thread.currentThread().getName() + " get data:" + data);

MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();

System.out.println("B from " + Thread.currentThread().getName()

+ " getMyData: " + myData.getName() + "," + myData.getAge());

}

}

}

//一个绑定当前线程的类

class MyThreadScopeData {

private static ThreadLocal map = new ThreadLocal<>();

private String name;

private int age;

private MyThreadScopeData() {

}

//定义一个静态方法,返回各线程自己的实例

//这里不必用同步,因为每个线程都要创建自己的实例,所以没有线程安全问题。

public static MyThreadScopeData getThreadInstance() {

//获取当前线程绑定的实例

MyThreadScopeData instance = map.get();

if (instance == null) {

instance = new MyThreadScopeData();

map.set(instance);

}

return instance;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

}

Thread-1 put random data:-1041517189

Thread-0 put random data:-98835751

A from Thread-1 getMyData: name-1041517189,-1041517189

A from Thread-0 getMyData: name-98835751,-98835751

B from Thread-1 getMyData: name-1041517189,-1041517189

B from Thread-0 getMyData: name-98835751,-98835751

5、实例

设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1,写出程序。

(1)如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如,卖票系统就可以这么做。

public class SellTicket {

//卖票系统,多个窗口的处理逻辑是相同的

public static void main(String[] args) {

Ticket t = new Ticket();

new Thread(t).start();

new Thread(t).start();

}

}

/**

* 将属性和处理逻辑,封装在一个类中

*

* @author yang

*/

class Ticket implements Runnable {

private int ticket = 10;

public synchronized void run() {

while (ticket > 0) {

ticket--;

System.out.println("当前票数为:" + ticket);

}

}

}

(2)如果每个线程执行的代码不同,这时候需要用不同的Runnable对象,例如,设计2个线程。一个线程对j增加1,另外一个线程对j减1,银行存取款系统。

public class MultiThreadShareData {

private int j;

public static void main(String[] args) {

MultiThreadShareData multiThreadShareData = new MultiThreadShareData();

for(int i=0;i<2;i++){

new Thread(multiThreadShareData.new ShareData1()).start();//增加

new Thread(multiThreadShareData.new ShareData2()).start();//减少

}

}

//自增

private synchronized void Inc(){

j++;

System.out.println(Thread.currentThread().getName()+" inc "+j);

}

//自减

private synchronized void Dec(){

j--;

System.out.println(Thread.currentThread().getName()+" dec "+j);

}

class ShareData1 implements Runnable {

public void run() {

for(int i=0;i<5;i++){

Inc();

}

}

}

class ShareData2 implements Runnable {

public void run() {

for(int i=0;i<5;i++){

Dec();

}

}

}

}

Thread-0 inc 1

Thread-0 inc 2

Thread-0 inc 3

Thread-0 inc 4

Thread-0 inc 5

Thread-1 dec 4

Thread-1 dec 3

Thread-2 inc 4

Thread-2 inc 5

Thread-2 inc 6

Thread-2 inc 7

Thread-2 inc 8

Thread-1 dec 7

Thread-1 dec 6

Thread-1 dec 5

Thread-3 dec 4

Thread-3 dec 3

Thread-3 dec 2

Thread-3 dec 1

Thread-3 dec 0


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:华为设备vlan聚合配置命令(华为创建vlan及端口分配)
下一篇:华为设备配置通过管理VLAN实现远程管理设备(华为交换机的管理vlan)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~