區域性變數一定執行緒安全嗎
阿新 • • 發佈:2019-01-25
區域性變數, 如果是基本型別或是包裝型別, 依然不能通過多執行緒改變其值, 如果是物件, 則其屬性值是執行緒不安全的
demo1:
public void compute(LocalDate date){ //在切換租戶時,只有當前執行緒的第一個租戶id設定有效,或者說一個執行緒內無法切換資料來源 TenantContext.set("saas_base"); List<TenantInfo> tenantInfoDtos = tenantInfoDao.getByStatus(1); CountDownLatch status = new CountDownLatch(tenantInfoDtos.size()); tenantInfoDtos.forEach(x->threadPoolTaskExecutor.execute(new InnerThread(x.getTenantId(), date, status))); try { status.await(); } catch (InterruptedException e) { e.printStackTrace(); } log.info(date+":DailyDataReportTask執行完成"); }
demo2: 輸出為0
@Test public void textTask(){ int i = 0; for(int j=0;j<10000;j++){ pool.execute(new InnerThread(i));} try { TimeUnit.SECONDS.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(i); } class InnerThread implements Runnable{ public int i; public InnerThread(int i){ this.i=i; } public void run(){ i=i+1; } }
demo3 輸出9963
@Setter
@Getter
@AllArgsConstructor
public class Testsss {
int i;
}
@Test public void textTask(){ Testsss t = new Testsss(0); for(int j=0;j<10000;j++){ pool.execute(new InnerThread(t));} try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(t.getI()); } class InnerThread implements Runnable{ public Testsss t; public InnerThread(Testsss t){ this.t=t; } public void run(){ t.setI(t.getI()+1); } }
demo4: 輸出10000
@Test
public void textTask() {
Testsss t = new Testsss(0);
for (int j = 0; j < 10000; j++) {
pool.execute(new InnerThread(t));
}
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.getI());
}
class InnerThread implements Runnable {
public Testsss t;
public InnerThread(Testsss t) {
this.t = t;
}
public void run() {
synchronized (t) {
t.setI(t.getI() + 1);
}
}
}