线程(五)ThreadLocal解决线程范围内数据的共享及疑问?

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014252478/article/details/83508905

1、该方法缺点是只能放入一个数据

package 多线程;

import java.util.Random;

//ThreadLocal来完成线程范围内数据的共享
public class pthread {
	
	private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
	
	public static void main(String[] args) {
		for (int i = 0; i < 2; i++) {
			new Thread(new Runnable() {
				
				@Override
				public void run() {
					// TODO Auto-generated method stub
					int data = new Random().nextInt();
					System.out.println(Thread.currentThread().getName() + " has put a data: " + data);
					threadLocal.set(data); //将数据直接扔进去
					new TestA().getData();
					new TestB().getData();
				}
			}).start();
		}
	}
	
	static class TestA {
		public void getData() {
			System.out.println(" A get data from " + Thread.currentThread().getName() + ":" + threadLocal.get());
		}
		
	}
	
	static class TestB {
		public void getData() {
			System.out.println(" B get data from " + Thread.currentThread().getName() + ":" + threadLocal.get());
		}
		
	}
	

}

2、放入多个数据,如下:

public class ThreadScopeShareData {
//不需要在外面定义threadLocal了,放到User类中了
//  private static ThreadLocal<User> threadLocal = new ThreadLocal<User>();

    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() + " has put a data: " + data);

                    //这里直接用User去调用getThreadLocal这个静态方法获取本线程范围内的一个User对象
                    //这里就优雅多了,我完全不用关心如何去拿该线程中的对象,如何把对象放到threadLocal中
                    //我只要拿就行,而且拿出来的肯定就是当前线程中的对象,原因看下面User类中的设计
                    User.getThreadInstance().setName("name" + data);
                    User.getThreadInstance().setAge(data);

                    new TestA().getData();
                    new TestB().getData();
                }
            }).start();
        }
    }

    static class TestA {
        public void getData() {
            //还是调用这个静态方法拿,因为刚刚已经拿过一次了,threadLocal中已经有了
            User user = User.getThreadInstance();
            System.out.println("A get data from " + Thread.currentThread().getName() + ": " 
                    + user.getName() + "," + user.getAge());
        }
    }

    static class TestB {
        public void getData() {

            User user = User.getThreadInstance();
            System.out.println("A get data from " + Thread.currentThread().getName() + ": " 
                    + user.getName() + "," + user.getAge());
        }
    }

}

class User {

    private User() {}

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

    //注意,这不是单例,每个线程都可以new,所以不用synchronized,
    //但是每个threadLocal中是单例的,因为有了的话就不会再new了
    public static /*synchronized*/ User getThreadInstance() {
        User instance = threadLocal.get(); //先从当前threadLocal中拿
        if(instance == null) {
            instance = new User();
            threadLocal.set(instance);//如果没有就新new一个放到threadLocal中
        }
        return instance; //向外返回该User
    }

    private String name;
    private int age;
    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;
    }
}

这个方法可以一次放入多个数据,并且通过类似单例的方式,不需要在将new出来的对象存入threadLocal中。

以上方法是看武哥的文章。

3、在实际项目中,常常会遇到线程内数据共享的问题,我就遇到类似问题:

//privat static int nTimes = entry.getKey();


.........


ScheduledFuture<?> scheduledFuture = pool.scheduleWithFixedDelay(new Runnable()
 {
      int nTimes = 0;
       @Override
       public void run() {
              nTimes++;
              Map jsonMap = JacksonUtil.json2Bean(message, Map.class);
              int ChargeLastTime = Integer.parseInt((String) jsonMap.get("EndTime")) - Integer.parseInt((String) jsonMap.get("StartTime")); //充电时长
              chargeOrderInfoReqVo.setUserName((String) jsonMap.get("UserName"));
              chargeOrderInfoReqVo.setStationID((String) jsonMap.get("StationID"));  //运营商自定义唯一编码?
              chargeOrderInfoReqVo.setEquipmentID((String) jsonMap.get("EquipmentID")); //运营商设备唯一编码?
              chargeOrderInfoReqVo.setConnectorPower(Float.parseFloat((String) jsonMap.get("ConnectorPower")) / 1000);
               chargeOrderInfoReqVo.setChargeLast(ChargeLastTime);
               chargeOrderInfoReqVo.setMeterValueStart(Float.parseFloat((String) jsonMap.get("MeterValueStart")) / 100);
               chargeOrderInfoReqVo.setMeterValueEnd(Float.parseFloat((String) jsonMap.get("MeterValueEnd")) / 100);
               LOG.info("------延时------");
               try {
                    Thread.sleep(150000 * nTimes);
               }catch (InterruptedException e){
                        e.printStackTrace();
               }
         }
 }, 10, nTimes * 10, TimeUnit.SECONDS);

我的想法是想要线程每执行一次,就延长一次,同时延长间隔变长,貌似如上好像可以。但在实际过程中,nTimes是一个定值;

意思就是线程类的nTimes * 10并没有变化,这个问题还需要继续研究。。。

猜你喜欢

转载自blog.csdn.net/u014252478/article/details/83508905