基于 Vue3 打造前台+中台通用提效解决方案(源码齐全网盘分享)

#1

基于 Vue3 打造前台+中台通用提效解决方案(源码齐全网盘分享)

超清原画 完整无密 资料齐全 获取ZY:百度网盘

Java 多线程不平安场景举例

  • 线程不平安的例子
    • 对象援用的逸出
    • 躲藏的逸出
    • 多个线程操作同一非线程平安对象
    • 运用不同的锁锁定同一对象
    • 同时操作多个关联的线程平安对象
  • 总结

线程不平安的例子

1.对象援用的逸出

即便一个对象是线程平安的不可变对象,指向这个对象的援用也可能不是线程平安的
public void Calculator{
    private ImmutableValue currentValue = null;
    public ImmutableValue getValue(){
        return currentValue;
    }
    public void setValue(ImmutableValue newValue){
        this.currentValue = newValue;
    }
    public void add(int newValue){
        this.currentValue = this.currentValue.add(newValue);
    }
}
复制代码

Calculator类持有一个指向ImmutableValue实例的援用。经过setValue()办法和add()办法可能会改动这个援用。因而,即便Calculator类内部运用了一个不可变对象,但Calculator类自身还是可变的,因而Calculator类不是线程平安的。换句话说:ImmutableValue类是线程平安的,但运用它的类不是。

2.躲藏的逸出

public class ThisEscape {
    public ThisEscape(EventSource source) {
        //隐式的使this援用逸出
        source.registerListener(new EventListener() {
            public void onEvent(Event e) {
                doSomething(e);
            }
        });
    }
    void doSomething(Event e) {
        //do sth.
    }
    interface EventSource {
        void registerListener(EventListener e);
    }
    interface EventListener {
        void onEvent(Event e);
    }
    interface Event {
    }
}
复制代码

当线程 1 和线程 2 同时访问 ThisEscape 结构办法,这时线程 A 初始化还未完成,此时由于 this 逸出,招致 this 在 1 和 2 中都具有可见性,线程 2 就能够经过 this 访问 doSomething(e) 办法,招致修正 ThisEscape 的属性。

3.多个线程操作同一非线程平安对象

public class NotThreadSafe{
    StringBuilder builder = new StringBuilder();
    
    public add(String text){
        this.builder.append(text);
    }	
}
//调用方
NotThreadSafe sharedInstance = new NotThreadSafe();
new Thread(new MyRunnable(sharedInstance)).start();
new Thread(new MyRunnable(sharedInstance)).start();
public class MyRunnable implements Runnable{
  NotThreadSafe instance = null;
  
  public MyRunnable(NotThreadSafe instance){
    this.instance = instance;
  }
  public void run(){
    this.instance.add("some text");
  }
}
复制代码

线程 1 和 线程 2 同时操作了同一个对象。并且这个对象并没有做线程平安的处置。

4.在同一对象上运用不同的锁

public class ListHelper { 
    public List list = 
        Collections.synchronizedList(new ArrayList());
        
    // 与 List 运用的不是同一把锁
    public synchronized boolean putIfAbsent(E e) {
        boolean absent = !list.contains(x);
        if (absent) {
            list.add(x);
        }
        return absent;
    }
}
复制代码

固然从代码上看像是线程平安代码,但是由于运用的锁与 list 的锁不是同一把锁,因而在多线程下依然会出问题。

5.同时操作多个关联的同步对象

public class NumberRange{
    private final AtomicInteger lower = new AtomicInteger(0);
    private final AtomicInteger upper = new AtomicInteger(0);
    
    public void setLower(int i) {
        //不平安的先检查,后执行
        if (i > upper.get()) {
            throw new Exception("");
        }
        
        lower.set(i);
    }
    
    public void setUpper(int i) {
        if (i < lower.get()) {
            throw new Exception("");
        }
        
        upper.set(i);
    }
    
    public boolean isInRange(int i) {
        return (i >= lower.get() && i <= upper.get());
    }   
    
}
复制代码

固然 lower 和 upper 都是线程平安的对象。但是它们之间并不是独立的。 存在当线程 1 调用 setLower(5), 线程 2 调用 setUpper(4),那么有可能产生的结果是两个线程均判别经过的「时序问题」,然后呈现 lower 大于 upper 的状况。

总结

以上就是线程不平安的代码常见场景举例,在实践的开发中,很有可能是较为隐晦的,但是场景根本都是上面的一种或多种场景共同呈现。因而实践排查线程平安问题的过程中,查看代码中有无上述的场景即可。