java并发编程: 基础部分

2018-02-07  本文已影响21人  神之试炼者

捡重要的记录

目的

充分利用系统资源. 提升程序性能.
常见问题:
线程A和线程B同时更新value
 @NotThreadSafe      这只是个说明性注解, 并不保证类的线程安全性, 安全性要自己实现
 public class UnsafeSequence{
     private int value;
     public int getNext(){ 
         return value++;
      } 
}

用synchronized修正上面的代码:

 @ThreadSafe      //记住这个只是文档性注解,安全性要自己实现
 public class UnsafeSequence{
   @GuardedBy("this")    // 指明value的一致性由对象自己负责
   private int value;

   public synchronized int getNext(){  
      return value++;  
  }
}

常见文档性注解说明:

下面都是文档性注解, 不要指望加这类注解就实现一致性.

类注解:
@ThreadSafe,
@NotThreadSafe,
@Immutable
    描述该类是不可变的. immutable的类自然是threadsafe的.
域注解和方法注解:
@GardedBy(lock)
    lock可以是:"this", "fieldName", "ClassName.fieldName","methodName()","ClassName.class"
    描述该域(或方法)的一致性应该由某个属性保证


文档注解的好处:

  1. 使用者一眼就知道类的特性
  2. 维护者需要根据这个协定保证并发特性
  3. 一些代码分析工具根据这些注解验证类实现是否和文档一致
4. 能通过文档性注解展示锁和状态保护, 哪天代码改变了状态(新增域或方法), 能通过文档提醒修改者注意保证并发特性.

多线程中额外的性能损耗: 上下文切换的损耗

java中首要的同步机制是:

synchronized, volatile,显示锁和原子变量

三种方案解决多线程问题:
1. 不要跨线程共享便变量;
2. 使共享变量不可变;
3. 在任何访问状态变量的时候使用同步;

相比同步, 良好的设计更重要!!!

完全由线程安全类构成的程序未必是线程安全的....只有当类封装了自己的状态时. "线程安全类"才有意义.

无状态对象永远是线程安全的
比如servlet, 再比如spring的单例模式, 虽然是有状态的, 但是如果状态变量没有修改操作. 仍然是线程安全的.

count++;
自增操作看上去是单独的, 实际上却是3个离散操作的简写:
读 - 改 - 写

  //java自带的线程安全计数器
  private final AtomicLong count = new AtomicLong(0);

volatile: 弱同步
确保对一个变量的更新以可预见的方式告知其他线程
原理:
编译器和运行时会监听volatile修饰的变量: 它是共享的, 对它的操作不会与其他的内存操作一起被重排序, volatile变量不会缓存在寄存器, 也不会缓存在其他处理器看不到的地方. 所以, 读volatile变量的时候总能读到某个线程写入的最新值.

volatile关键字 不足以支持自操作的原子性!

ThreadLocal:每个线程会维护一份自己的拷贝, 从而实现线程封闭

不可变对象永远是线程安全的.

To Be Continued...

上一篇下一篇

猜你喜欢

热点阅读