一文看完《Java多线程编程核心技术》这本书(下)

其实消费者生产者问题一讲完,这本书就基本就被读的很薄了,后面的内容感觉都已经不算核心了,从线程角度看单例模式还有点意思,其他自己感觉没必要看。。。。

chapter4——Lock的使用

Java多线程中,可以使用synchronized关键字实现线程之间的同步互斥,但在JDK1.5之中新增加了ReentrantLock也能达到同样的效果,并且在扩展功能上也更加强大,比如嗅探锁定、多路分之通知的功能,而且在使用上也比synchronized更加的灵活。

ReentrantLock

ReentrantLock实例使用lock.lock()时,持有的是对象监视器,其他线程只有等待锁被释放时再次争抢,效果和synchronized一样。

Condition实现wait/notify

Condition类时1.5以后出现的,具有很好的灵活性。

多路通知

可以在一个Lock对象中创建多个Condition(对象监视器)实例,线程对象可以注册在指定的Condition中,从而有选择地进行程线通知,在调度线程上更加灵活。

选择通知

notify进行通知时,是JVM随机选择的,但使用ReentrantLock结合Condition类可以实现有选择的通知。
具体可以参见chapter4.t03_UseMoreCondition

公平锁和非公平锁

公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即FIFO
非公平锁表示一种获取锁的抢占机制,是随机获得锁的,可能某些线程永远拿不到锁

Lock的一些方法

具体使用参见:t06_someMethod

int getHoldCount()

查询当前线程保持此锁定的个数,也就是当前线程调用lock()方法的次数。

int getQueueLength()

返回正在等待获取此锁定的线程估计数,比如5个线程,1个线程执行await方法,那么getQueueLength的结果就是4

int getWaitQueueLength(Condition condition)

返回等待与此锁定相关的给定条件Condition的线程估计数

boolean hashQueuedThread(Thread thread)

查询指定的线程是否正在等待获取此锁定

boolean hashQueuedThreads()

查询是否有线程正在等待获取此锁定

boolean hasWaiters(Condition condition)

查询是否有线程正在等待与此锁定有关的condition

boolean isFair()

判断锁是不是公平锁,lock默认是非公平锁

isHeldByCurrentThread()

判断当前线程是否持有这个锁。

isLocked()

判断此锁定是不是由任意线程持有.

void lockInterruptibly()

如果当前线程未被中断,则获取锁定,如果已经被中断则会有异常

boolean tryLock()

仅在调用时锁定未被另一个线程保持的情况下,才获取该锁定

boolean tryLock(Long timeout, TimeUnit unit)

如果在锁定的时间内没有被另一个线程持有,而且当前线程未被中断,则拿到这个锁

void awaitUninterruptibly()

await过程中interrupt不会报错

ReentrantReadWriteLock

ReentrantLock具有完全排他的效果,同一时间只有一个线程在执行ReentrantLock.lock()方法后面的任务。这样确实保证了线程执行的安全性,但是效率很低下。
所以ReentrantReadWriteLock就解决了这个问题,使用它可以加快运行速度,在某些不需要操作实例变量的情况下,完全可以使用这种锁去替换ReentrantLock。

读写操作有两个锁,读操作相关的是共享锁,写操作相关的是排他锁。
读锁之间不互斥,一个写锁和其他任意类型的锁都互斥
可以同时读,但另外一方面:第一不同同时写,第二有线程写不能读,第三有线程读不能写

chapter5——定时器Timer

定时/计划功能在移动开发领域较多,比如Android技术,定时计划任务功能在java中主要使用的就是Timer对象,Timer在内部还是使用多线程的方式进行处理,所以它和线程有很大的关系。

使用Timer

Timer就是负责计划任务的功能,也就是在指定的时间开始执行某一个任务,但是封装任务的类却是TimerTask类。执行计划任务的代码要放在TimeTask的子类中。

基本使用

如果设定的执行任务的时间早于当前时间,则立即执行task任务。
TimerTask是以队列的方式一个一个被顺序性执行,所以执行的时间可能比设定的时间要晚。

撤销

主要区分TimeTask和Timer的取消。具体参见t02_taskLoop

scheduleAtFixedRate

scheduleAtFixedRate和schedule的区别在于如果设定的时间靠前,又是循环的话,scheduleAtFixedRate会先把中间间隔时间应该做的任务补出来。具体参见

chapter6——单例模式与多线程

这个设计模式说过一遍了,这次从线程的角度再看一遍。

立即加载/饿汉模式

在调用方法前,实例已经被创建了。
idea默认的模版Singleton就是饿汉模式。
饿汉模式基于 classloader 机制避免了多线程的同步问题。
缺点就是不能有其他实例变量

延迟加载/懒汉模式

不加锁,多线程可能会有多个实例,所有不算单例模式
加锁,既然多线程同时进入getInstance()方法,那就对这个方法加锁,结果就是支持多线程,但是效率会变低
加锁可以同步方法,也可以同步代码块。

DCL

double-checked locking,采用双锁机制,安全且在多线程情况下能保持高性能。
大多数的解决方案。

静态内部类

这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。

序列化

一个字节八个比特,就是八个二进制位 四个二进制数最大表示为15,就是一个16进制数。所以生成的字节码文件应该两个两个的看,因为2个16进制数是一个字节共8位。
序列化文件可参照ObjectStreamConstants类。

readResolve方法的返回值会替换原来反序列化的对象,保证反序列化的机构一定是枚举类的值或者静态内部类。主要产开《疯狂java讲义》那本书。
https://blog.csdn.net/u014653197/article/details/78114041

枚举类

这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。不过,由于 JDK1.5 之后才加入 enum 特性,用这种方式写不免让人感觉生疏,在实际工作中,也很少用。

chapter7——拾遗增补

线程的状态

线程有6个状态:
NEW:至今尚未启动的线程处于这个状态
RUNNABLE:正在虚拟机中执行的线程处于这个状态
BLOCKED:受阻塞并等待某个锁的线程处于这个状态
WAITING:等待另一个线程来执行某一个操作
TIMED WAITING:等待另一个线程但是指定了等待时间
TERMINATED:已经退出的线程

其他实在没什么,略

发表评论

电子邮件地址不会被公开。