捡重要的记录
目的
充分利用系统资源. 提升程序性能.
常见问题:
![](https://img.haomeiwen.com/i1708412/37fcb240530ee1d1.png)
@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"
描述该域(或方法)的一致性应该由某个属性保证
文档注解的好处:
- 使用者一眼就知道类的特性
- 维护者需要根据这个协定保证并发特性
- 一些代码分析工具根据这些注解验证类实现是否和文档一致
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...
网友评论