ThreadLocal同步
package com.example.demo; // 自定义一个引用类型 public class Value<T> { private T value; public void set(T _value) { value = _value; } public T get() { return value; } }
改造后
package com.example.demo; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashSet; @RestController public class StatController { static HashSet<Value<Integer>> set = new HashSet<>(); static ThreadLocal<Value<Integer>> count = new ThreadLocal(){ @Override protected Value<Integer> initialValue() { Value<Integer> value = new Value<>(); value.set(0); addSet(value); return value; } }; synchronized static void addSet(Value<Integer> value){ // 临界区操作 set.add(value); } void __add() throws InterruptedException { Thread.sleep(100L); Value<Integer> value = count.get(); value.set(value.get() + 1); } @RequestMapping("/stat") public Integer stat(){ return set.stream().map(x->x.get()).reduce((a, b) -> a+b).get(); } @RequestMapping("/add") public Integer add() throws InterruptedException { __add(); return count.get().get(); } } $ ab -n 10000 -c 100 localhost:8080/add $ curl localhost:8080/stat 10000
总结
- 完全避免同步(困难)
- 缩小同步范围(简单)+ ThreadLocal解决问题
源码分析
- Quartz: SimpleSemaphore
- MyBatis: SqlSessionManager
- Spring
本地事务
A Atomic 原子性 操作不可分割
C Consistency 一致性 任何时刻数据都能保持一致
I Isolation 隔离性 多事务并发执行的时序不影响结果
D Durability 持久性 对数据接收的存储是永久的
自定义实现ThreadLocal
package com.demo.threadlocal; import java.util.HashMap; import java.util.concurrent.atomic.AtomicInteger; /** * 自定义实现ThreadLocal * * @param <T> */ public class MyThreadLocal<T> { // 自增接口保证唯一性 static AtomicInteger atomic = new AtomicInteger(); // 高德纳 hash值 Integer threadLocalHash = atomic.getAndAdd(0x61c88647); static HashMap<Thread, HashMap<Integer, Object>> map = new HashMap<>(); // 临界区上锁 synchronized static HashMap<Integer, Object> getMap() { Thread thread = Thread.currentThread(); if (!map.containsKey(thread)) { map.put(thread, new HashMap<>()); } return map.get(thread); } protected T initialValue() { return null; } public T get() { System.out.println("atomic: " + atomic); HashMap<Integer, Object> map = getMap(); if (!map.containsKey(this.threadLocalHash)) { map.put(this.threadLocalHash, this.initialValue()); } return (T) map.get(this.threadLocalHash); } public void set(T val) { HashMap<Integer, Object> map = getMap(); map.put(this.threadLocalHash, val); } }
package com.demo.threadlocal; public class TestMyThreadLocal { static MyThreadLocal<Long> threadLocal = new MyThreadLocal(){ @Override protected Long initialValue() { return Thread.currentThread().getId(); } }; public static void main(String[] args) { for (int i = 0; i < 100; i++) { new Thread(()->{ System.out.println(threadLocal.get()); }).start(); } } }