執行緒(五)ThreadLocal解決執行緒範圍內資料的共享
阿新 • • 發佈:2018-12-18
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並沒有變化,這個問題還需要繼續研究。。。