Java线程学习笔记(4)

2022-03-05  本文已影响0人  哦呵呵_3579

每个工作线程都需要从主存中拷贝一份变量到自己的工作内存中,当一个变量被lock的时候,会清除其在工作内存中的数据,等使用的时候重新从主存中读取。

当变量的锁被一个线程占有之后,其他线程就不能获取到他的锁,所以无法从主存中获取到他的数据,只能等待锁的释放,从而确保了数据的安全性。

而被标记了volatile的变量,当发生变更的时候会通知到其他使用它的线程,使其全局可见,但是不能保证其数据的安全性,依旧存在竞态条件问题。

JVM会把64位的long和double拆分成两个32位进行操作,因此存在安全性问题。

如何保证线程安全

线程封闭

1、Ad-hoc线程封闭
例如Volatile就是一个特殊的情况,当只有一个线程写入,其他线程只读的情况下就是线程安全的

2、栈封闭
方法内的局部变量都是线程安全的

3、ThreadLocal
ThreadLocal类对于每个线程会有一份独立的副本,每个线程之间的数据都是相互独立不受影响的,例如数据库的连接池

不变性

1、final
final对象是不可变的,所以正确构造的final对象一定是线程安全的

对象创建以后其状态就不能修改
对象的所有域都是final类型
对象是正确创建的

除非需要更高的可见性,否则应该将所有的域都设置为private

2、使用线程安全的容器
k-v:Hashtable、synchronizedMap、ConcurrentMap、ConcurrentHashMap
value:Vector、CopyOnWriteArrayList、CopyOnWriteArraySet
队列:BlockingQueue、ConcurrentLinkedQueue

3、锁
synchronized
volatile

同步工具类

闭锁

CountDownLatch--指定启动时的状态,await方法会一直阻塞,直到countDown到0为止会往下执行,适合做并发测试

栅栏

CyclicBarrier--定义一个值以及需要执行的任务,当等待的线程数量与其一致的时候就开始执行任务,否则就阻塞,可以重复使用

FutureTask

FutureTask.get()

信号量

Semaphore--用于控制同一时间某个特定资源的操作数量,通过acquire个release这两个方法进行限制

Executors

newFixedThreadPool

newCachedThreadPool

newSingleThreadPool

newScheduledThreadPool

[https://www.processon.com/diagraming/5f490aa85653bb0c71dd9c8a](https://www.processon.com/diagraming/5f490aa85653bb0c71dd9c8a)


[https://www.processon.com/diagraming/5f4bae5ae401fd14b225a8c8](https://www.processon.com/diagraming/5f4bae5ae401fd14b225a8c8)

线程的关闭

Interrupt

调用未知的代码要使用try catch,避免因异常而导致线程挂掉

FutureTask.get()可以获取到异常,可以根据异常来进行处理

shutdown--等待任务处理完成之后安全退出
shutdownNow--立刻结束当前任务,并返回未执行任务列表

处理非正常异常的时候可以通过setUncaughtExceptionHandler来进行处理

JVM钩子
通过Runtime.getRuntime().addShutdownHook添加钩子

守护线程与普通线程
普通线程会等待,守护线程直接结束

上一篇下一篇

猜你喜欢

热点阅读