图解java多线程设计模式-第一章 Single Threaded Execution模式

以下内容是我在阅读《图解Java多线程设计模式》一书中的总结和思考

本章配语是:能通过这座桥的只有一个人

几个概念:

  1. SharedResource(共享资源):可以被多个线程访问的类,包含safeMethod和unsafeMethod。其中unsafeMethod就是在多线程环境下不安全的,需要同步的方法。
  2. Single Threaded Execution模式:同一时间内只能让一个线程执行处理。

在Single Threaded Execution模式中,满足以下全部条件时,死锁就会发生:

  1. 存在多个SharedResource角色
  2. 线程在持有某个SharedResource角色的锁的同时,还要获取其他SharedResource角色的锁才能完成任务
  3. 获取SharedResource角色的锁的顺序是对称相反的,例如先锁A再锁B,和先锁B再锁A,这样就是对称相反

以上条件有一个不满足,死锁就会破解。比如:

  1. 将多个SharedResource角色封装到一个类中,这样就变成只有一个SharedResource角色了
  2. 上锁的顺序全都一样,这样也不会发生死锁

注意,这只是针对Single Threaded Execution模式:同一时间只能让一个线程执行处理。而能够实现这样的关键就是对访问共享资源的方法(method)进行互斥处理,也就是synchronized。

所以,只要同一个类中的方法(method)标志了synchronized关键字,就说明这些方法(method)之间是互斥的。

 

可复用性和继承反常

如果子类能够访问SharedResource角色的字段,那么编写子类的开发人员就要注意,子类中的方法是否可以破坏安全性,因为子类对象可以随意访问SharedResource的字段。

对于多线程程序设计来说,继承会引起一些麻烦的问题,需要妥善处理。

 

临界区的大小和性能

临界区:上锁的区域,就是{}花括号之间的代码。

一般来说,临界区越大,性能就越低,发生线程冲突的概率就越高。

void method()
{
	synchronized (this)
	{
		// 线程无关的代码
		...
		// 真正需要同步的代码
	}
}

就以上代码,如果将线程无关的代码放到同步代码块中,那么明明不用等待就可以操作的代码却要花时间去等待,那么就会降低效率了。

 

synchronized在保护着什么

这个问题要考虑到两个方面,一个是要弄清保护什么,另一个是要确定保护成功。

保护的一般就是SharedResource,具体一点来说就是字段的值。

是否保护成功:

关于这个问题,是需要不断累积经验才能快速准确地判断的。比如说出现继承反常的情况(即父类字段可以被子类直接调用)。

又比如对于SharedResource,一般来说是要一起放到临界区之内的,如果出现类似如下代码,即SharedResource没有放在一起保护,这样也就没有意义了,达不到效果。

public synchronized void setName(String name)
{
	this.name = name;
}

public synchronized void setAddress(String address)
{
	this.address = address;
}

 

原子操作

是否是原子操作对于是否需要上锁有比较大的影响。如果一个方法里面只有一个原子操作,那么就没有必要上锁了。

一般来说:基本数据类型和引用操作都是原子操作,但:double和long的操作就不是原子操作。还有,++和--也不是原子操作。

 

Semaphore类

java.util.concurrent包提供了表示计数信号量的Semaphore类。

这个有空再贴代码上来吧

你可能感兴趣的:(阅读)