进程是系统的基本调度单位
多线程的作用:充分发挥多处理器的优势、提高系统性能、提高系统的吞吐率。
多线程的风险:安全性问题(出现不可预料或者错误的值)、活跃性问题(无限循环等)、性能问题(不合理的多线程导致线程切换频繁反而降低性能)
线程安全性:当多线程访问某个类时,这个类始终能表现出正确的行为,那么这个类就是线程安全的。
无状态对象一定是线程安全的。
有状态就是有数据存储功能。有状态对象(Stateful Bean),就是有实例变量的对象 ,可以保存数据,是非线程安全的。在不同方法调用间不保留任何状态。其实就是有数据成员的对象。
无状态就是一次操作,不能保存数据。无状态对象(Stateless Bean),就是没有实例变量的对象。不能保存数据,是不变类,是线程安全的。具体来说就是只有方法没有数据成员的对象,或者有数据成员但是数据成员是可读的对象。
servlet就是一个无状态的对象
count++不是个原子操作,它分为3部分:读取、修改和保存
竞态条件:当某个计算的正确性取决于多线程交替执行的时序时,就会产生竞态条件。最常见的就是“先检查后执行”。
“先检查后执行”类型的竞态条件:基于一种可能失效的观察结果来做出判断或者执行某个计算。
例如延迟初始化中会发生竞态条件。因为在判断是否存在对象对象引用时,如果有另一个线程同时访问它,则两个线程会返回不同的实例。
延迟加载:目的是为了在需要使用时才创建实例。比如某个系统在启动时会加载大量的类,但是有很多并没有用到,而采取延迟加载则可以提高系统的启动速度。
单例模式:保证多个线程使用到的是同一个实例。
单例模式的写法:
public static Singleton getInstance(){
if (instance == null)
synchronized(instance){
if(instance == null)
instance = new Singleton();
}
return instance;
}
首先调用getInstance(),判断instance是否为null,不为null则返回实例,否则将按顺序执行到同步代码块,保证在创建Singleton的时候只有一个线程访问。然后再返回实例。
//更巧妙的写法
public class Singleton{
private Singleton(){
…
}
private static class SingletonContainer{
private static Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return SingletonContainer.instance;
}
}
关于单例模式的一篇好文章:
https://www.cnblogs.com/jingpeipei/p/5771716.html
- Java的内置锁synchronized block(同步代码块),是一种互斥锁,即最多只有一个线程可以持有这个锁。
- 重入:当一个线程获取由它自己持有的锁时,请求可以成功。