Java 并发编程

Java并发编程笔记:总结

2018-07-15  本文已影响2人  yeonon

《Java并发编程实战》是Java并发编程领域中的一本著作,我是第二次再读这本书的时候才敢下笔写这个系列的笔记,主要是因为这本书前后关联性是比较大的(第一次读之前大致浏览过,所以知道这点),需要对并发有一个整体认识,才能将知识点写得正确。下面是一些重要的知识点:

进程和线程

进程

进程是运行在操作系统中的程序,是操作系统资源管理的最小单位。

线程

线程是轻量级的进程,位于进程内部,进程内部的多个线程共享该进程打开的文件,代码,可共享数据等。因为Java程序运行在一个进程里,所以Java并发编程绝大多数面对的是线程,即多线程编程。

线程安全

多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么这个类是线程安全的。

保证线程安全是并发编程的首要任务,只有保证了线程安全(即正确性),其他优化才有意义。

可见性即原子性

可见性

可见性即在多线程环境下,某个线程对某个状态做了改变,这个改变能立即被其他线程感知到。保证可见性是要做一些特殊处理的,因为Java内存模型(JMM)规定了每个线程都有自己的工作内存,工作内存里保存着状态的拷贝,如果没有特殊处理,线程对状态的操作会更新到拷贝上,后续会将其更新到主内存中,但是其他线程访问这个状态时,并不会去主内存中拉取新的值(原因是这不符合缓存原理),这就导致了其他线程将会读取到失效的数据,最终导致线程不安全。

在Java中,保证可见性的一种方式是使用volatile关键字修饰字段,当检测到这个字段状态是volatile修饰时,系统会将修改强制刷新,其实可以理解成取消缓存。

原子性

原子性即一个或多个操作是不可分割的,一旦执行,一定会执行完毕,期间不能有其他线程的干扰。学习数据库事务是理解原子性的一个好方法。

同步工具

Java提供了很多同步工具供用户使用,用户可以使用这些工具构建并发系统,这些工具往往使用起来非常简单但功能强大,这多亏了Java语言的设计师们。同步工具类大多存在于J.U.C包下。例如CountDownLatch,ConcurrentHashMap等。

线程池

线程池是提高线程复用率的一种高效的手段,在高并发的环境下,如果频繁的创建,销毁线程会导致系统的整体吞吐量降低,将多个线程池化可以减少创建线程,销毁线程的开销。

Java中的线程池Executor框架,具体如何使用可以看看源码,源码写得比较清楚。

活跃性问题

活跃性问题这个词不好解释,这里的活跃性指的是线程的活跃性,线程太活跃或者不活跃都是不好的,这就是活跃性的问题(解释的有些太难理解)。例如死锁,活锁,饥饿等等。

在并发编程中我们应该尽量避免出现活跃性问题,例如使用银行家算法预防死锁的发生,例如使用公平锁来防止饥饿(也许会降低吞吐量)

Java中有内置锁和显式锁,内置锁即synchronized,内置锁使用起来比较方便,但是不够灵活,显式锁有很多,例如ReentrantLock,ReadWriteLock等,显式锁需要显式的lock和unlock,一般配合try-finally结构保证unlock一定执行。显式锁主要特性是灵活,其性能在新的JDK中已经不具备太多优势,因为Java语言的设计师们好像一直在向优化内置锁的方向努力。

锁可以说是保证线程同步最基本的,最简单直接的方式了,所以性能不会太好,尤其是线程竞争激励的时候。除了锁还有一种手段就是CAS操作,通过轮询来检查状态是否满足条件,当满足条件的时候,就改变状态,不满足则继续轮询,是一种比较高效的同步手段(AtomicXXX类大量使用了CAS操作),具体的参见其他文章。

小结

写到这里,本系列笔记告一段落了,其实书中后面还有一些内容,例如构建自定义的同步工具等,这些内容比较高级,目前我还太能理解,可能是“内力不足”吧,所以后面的内容没有写进来,主要是因为笔记发布在网络上,万一哪天被人看到了,误导了人家,那就不好了。

上一篇 下一篇

猜你喜欢

热点阅读