并发的很多问题在于,访问共享的可变状态时,可能会出现不可预估的错误。因此,需要进行正确的管理。
我们知道,可以通过同步代码块和同步方法以确保以原子的方式执行,或者用volatile确保可见性。这些都是实现并发的基础。
同步的一个重要的点在于:内存可见性。我们不仅仅希望防止某个线程正在使用对象状态而另一个线程在修改此状态,我们还需要保证,当一个线程修改了某个变量后,其他的线程能够立即看到。这必须使用一些同步的手段达到。
可以通过显示的同步,或者类库中内置的同步来保证对象被安全的发布。
需要搞懂以下点
可见性以及产生的后果
1.失效数据和竞态条件(由于不恰当的执行时许而出现不正确的结果)
2.非原子的64位操作(Java内存模型中,变量的读取和写入都是原子操作,但是64位的long和double不是,jvm允许他们分解成两个32位的。)
3.volatile:作用两个 1.保证可见性 2.拒绝指令重排(jvm层面的)
4,加锁与可见性:加锁可以保证同步互斥,还可以保证内存可见性。
发布与逸出
发布就是是对象能够在当前作用域之外使用,逸出则是在不应该被发布的时候发布了
线程封闭
就是在单线程内访问数据,这样就避免了同步。
JDBC swing等都用了线程封闭。swing通过EDT(event dispatch thread事件分发线程实现),JDBC,线程从连接池获取connection,再返回connection之前,都不会将其分配给别的线程。
1.栈封闭
只有局部变量能够访问对象
2,Threadlocal类
使得线程中的某个值与保存至的对象关联起来,提供get和set接口或者方法,这些方法为每一个使用该变量的线程都有一份独立的副本,因此get总是能够返回当前执行线程在调用set时设置的最新值。
通常用于防止对可变的单实例变量或者全局变量进行共享。
最后 不可变性
不可变的对象一定是线程安全的。在java中,final关键字提供不可变性。在Java内存模型中,final域能够确保初始化过程的安全性,从而可以不受限制的访问不可变的对象,共享这些对象时无需同步。