《java并发编程实战》笔记

时间:2023-12-17 12:55:44

《java并发编程实战》这本书配合并发编程网中的并发系列文章一起看,效果会好很多。

并发系列的文章链接为:  Java并发性和多线程介绍目录

建议: 《java并发编程实战》第3章和第4章可以暂时先跳过。。这部分内容的文字和概念很多,代码块偏少。不容易看进去。

一、线程
1.线程的使用可以提升程序的性能。
2.线程如果没有同步,操作的执行顺序是不可预测的。
3.线程之间共享数据时,必须使用同步机制。不然数据会发生无法预料的变化。
二、线程的安全性

0.线程安全性:当多个线程访问某个对象时,这个对象不会出错。
1.构建并发程序,必须正确使用线程和锁。要编码线程安全的代码,其核心在于要对状态访问操作进行管理,特别是共享和可变状态的访问。
2.竞态条件:在并发编程中,由于不恰当的执行时序而出现不正确的结果,称为“竞态条件”
3.加锁机制。
java提供了一种内置的锁机制来支持原子性:同步代码块
public synchronized void  methodName() {   }
4.假如,在并发编程中,使用synchronzied修饰service层的某个方法,在同一时刻只有一个线程可以执行该方法。
此时,该方法是线程安全的,但是多个客户端无法同时访问该方法,服务的响应效率非常低,性能差。
5.java并发中的特性。
原子性:即一个操作或者多个操作,要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。
内存可见性:确保当一个线程修改了对象状态后,其他线程可以看到发生的状态变化。
有序性:即程序执行的顺序按照代码的先后顺序执行。因为尽管jvm的指令重排序不会影响单个线程的执行,
但是会影响到线程并发执行的正确性。
6.同步,可以确保原子性,有序性,可见性。
三、对象的共享
1.如果多个线程同时访问同一个共享变量,没有使用同步机制会导致结果不可预测。
2.volatile这个关键字有什么用?
被volatile修饰的变量能够保证每个线程能够获取该变量的最新值,从而避免出现数据脏读的现象。

volatile变量只能确保可见性,而加锁机制既可以确保可见性,又可以确保原子性。

3.发布,是指使对象能够在当前作用域之外的代码中使用。
逸出,当某个不应该发布的对象被发布时,就称为逸出。
4.线程封闭,就是不在线程之间共享数据。线程封闭可以实现线程安全性。
ThreadLocal,保证了每个线程都有独立的对象副本,保证了对象的唯一性,维持线程的封闭性。

5.不变性,不可变对象一定是线程安全的。

6.final修饰的变量,具有不变性。

五、基础构建模块(介绍juc的api)

1.当普通的同步容器类,例如Vector,HashTable类,如果在迭代过程中被修改,就会抛出一个ConcurrentModificationException。

2.ConcurrentHashMap用于替代同步Map。ConcurrentHashMap基于锁分段技术。在这种机制下,任意数量的读取线程可以并发访问Map,执行读取操作的线程和执行写入操作的线程可以并发地访问Map,并且以一定数量的的写入线程可以并发地修改Map。

3.CopyOnWriteArrayList用于替代同步List。CopyOnWrite,"写时拷背",也就是在每次修改时,都会创建并重新发布一个新的容器副本,从而实现可变性。因此,多个线程可以同时对这个容器进行迭代,而不会彼此干扰或者与修改容器的线程相互干扰。

4.阻塞队列。生产者消费者模式。

阻塞队列先进先出。BlockingQueue。可进行put()和take()操作。

5.阻塞方法和中断方法。interruptedException。

6.并发工具类。闭锁CountCownLatch,信号量Semephore,栅栏Barrier

六、任务执行

1.主要讲Executor框架。为每个任务分配一个线程。

2.无限制创建线程的不足:线程生命周期的开销非常高;资源消耗大;稳定性有影响。

3.Callable和Future,返回通过future.get()获取执行结果。

4.CompletionService相当于将Executor和BlockingQueue的功能整合在一起。

七、取消与关闭

1.中断(interrupt)并不会马上停止目标线程正在进行的工作,而是改变中断状态。。等到调用wait()、sleep()、join()等方法时,才抛出中断的异常InterruptedException 。

2.恢复中断状态的方法:  Thread.currentThread().interrupt();

3.还通过Future来实现取消。Future拥有一个cancel(),方法。即  boolean cancel(boolean mayInterruptIfRunning);

可以通过设置mayInterruptIfRunning为true,取消任务。

十五、

1.非阻塞算法 : 如果在某种算法中,一个线程的失败或挂起不会导致其他线程也失败或挂起,那么这种算法就称为“非阻塞算法”

2.无锁算法: 如果在算法的每个步骤中都存在某个线程能够执行下去,那么这种算法也称为“无锁算法”

其他:

1.volatile变量的读/写和CAS可以实现线程之间的通信。

把这些特性整合在一起,就形成了整个concurrent包得以实现的基石。

如果我们仔细分析concurrent包的源代码实现,会发现一个通用化的实现模式:

  • 首先,声明共享变量为volatile;
  • 然后,使用CAS的原子条件更新来实现线程之间的同步;
  • 同时,配合以volatile的读/写和CAS所具有的volatile读和写的内存语义来实现线程之间的通信。

AQS,非阻塞数据结构和原子变量类(java.util.concurrent.atomic包中的类),这些concurrent包中的基础类都是使用这种模式来实现的,而concurrent包中的高层类又是依赖于这些基础类来实现的。从整体来看,concurrent包的实现示意图如下:

《java并发编程实战》笔记

疑问:

1.线程安全的概念。

多个线程对数据进行读写时,数据的读写等操作结果保持正确。

2.活跃性。

就是饥饿和公平。

3.竞态条件如何理解??

在并发编程中,由于不恰当的执行时序而出现不正确的结果。

4.@ThreadSafe,这个注解怎么用?

5.ThreadFactory如何理解?

用于创建线程,可以指定线程名称。

6.Future类有什么用?

比ExcutorService多返回一个结果。

7.无阻塞算法是什么?如何区别阻塞算法?

阻塞算法,比如BlockingQueue。。无阻塞算法,比如AtomicInteger.

8.java监视器模式。