多线程同步

任务

1.多线程访问临界资源
	1.1 多线程访问临界资源时的数据安全问题
	1.2 解决临界资源问题
	1.3 锁
	1.4 同步代码块
	1.5 同步方法
	1.6 ReentrantLock类
2. 死锁
3.多线程在单例中的应用
4.线程的通信
	4.1 原理
	4.2 实现

目标

1.了解多线程中临界资源问题产生的原因
2.掌握解决临界资源问题的方案
3.掌握锁的概念
4.掌握同步代码块和同步方法
5.了解ReentrantLock类的使用
6.掌握多线程在单例中的应用
7.了解死锁以及生产者与消费者设计模式

1.多线程访问临界资源

1.1 多线程访问临界资源时的数据安全问题
	产生原因:有多个线程在同时访问一个资源,如果一个线程在取值的过程中,时间片又被其他线程抢走了,临界资源问题就产生了
1.2 解决临界资源问题
	解决方案:一个线程在访问临界资源的时候,如果给这个资源“上一把锁”,这个时候如果其他线程也要访问这个资源,就得在“锁”外面等待
1.3 锁
对象锁:任意的对象都可以被当做锁来使用

	类锁:把一个类当做锁,语法为:类名.class   
1.4 同步代码块
语法:
	synchronized(锁) {
		//需要访问临界资源的代码段
	}

	说明:
	a.程序走到代码段中,就用锁来锁住了临界资源,这个时候,其他线程不能执行代码段中的代码,只能在锁外边等待
	b.执行完代码段中的这段代码,会自动解锁。然后剩下的其他线程开始争抢cpu时间片
	c.一定要保证不同的线程看到的是同一把锁,否则同步代码块没有意义

​ 2.2.1 同步代码块和对象锁的使用

 

​ 2.2.2 同步代码块和类锁的使用

 
1.5 同步方法

​ 2.3.1 同步非静态方法

 

​ 2.3.2 同步静态方法

 
1.6 ReentrantLock类
	通过显式定义同步锁对象来实现同步,同步锁提供了比synchronized代码块更广泛的锁定操作

	注意:最好将 unlock的操作放到finally块中

	通过使用ReentrantLock这个类来进行锁的操作,它实现了Lock接口,使用ReentrantLock可以显式地加锁、释放锁

​ 案例一:模拟售票

 

​ 案例二:模拟银行卡存取钱

 

2.死锁

​ 每个人都拥有其他人需要的资源,同时又等待其他人拥有的资源,并且每个人在获得所有需要的资源之前都不会放弃已经拥有的资源

​ 当多个线程完成功能需要同时获取多个共享资源的时候可能会导致死锁

 

3.多线程在单例中的应用

单例的实现方式:懒汉式和饿汉式

	其中,懒汉式是线程不安全的,当有多条线程同时访问单例对象时,则会出现多线程临界资源问题
3.1 多线程访问单例-饿汉式
 
3.2 多线程访问单例-懒汉式
 

4.线程的通信【生产者与消费者设计模式】

4.1 原理
它描述的是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者可以从仓库中取走产品,解决生产者/消费者问题,我们需要采用某种机制保护生产者和消费者之间的同步

	同步问题核心在于:如何保证同一资源被多个线程并发访问时的完整性,常用的方法就是加锁,保证资源在任意时刻只被一个线程访问

画图分析:

生产者与消费者设计模式

4.2 实现

​ 方式一:采用wait()、notify()和notifyAll()方法

wait():当缓冲区已满或空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等待状态,让其他线程执行

		·是Object的方法
		·调用方式:对象.wait();
		·表示释放 对象 这个锁标记,然后在锁外边等待(对比sleep(),sleep是抱着锁休眠的)
		·等待,必须放到同步代码段中执行	
notify():当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态

		·是Object的方法
		·调用方式:对象.notify();
		·表示唤醒 对象 所标记外边在等待的一个线程
notifyAll():全部唤醒

		·是Object的方法
		·调用方式:对象.notifyAll()
		·表示唤醒  对象 所标记外边等待的所有线程
 

​ 方式二:采用ReentrantLock类中的newCondition()方法结合Condition类中的await()、signal()和signalAll()方法

 

总结

课前默写

1.分别使用继承Thread类和实现Runnable接口的方式创建线程

2.设计程序,演示join方法的使用

作业

1.春运到了,某个火车站四个售票员出售某个车次最后100张车票的情形。
分析:
  	火车票:  临界资源
 	 四个售票员:四个线程实例  , 出售车票:卖一张,车票就少一张

2.使用线程安全的懒汉式实现之前的阿里巴巴董事长的题目

3.完善昨天的作业,模拟多个人通过一个山洞的模拟。这个山洞每次只能通过一个人,每个人通过山洞的时间为5秒,随机生成10个人,同时准备过此山洞,显示一下每次通过山洞人的姓名

面试题

1.多线程临界资源问题是如何产生的,该怎么解决

2.简述生产者与消费者设计模式的实现原理