JavaSE---多线程(三)
死锁
- 多个线程一起占有共享资源,并且都在等待其他线程释放资源,你等我,我等你,某一个同步块同时拥有
两个以上对象的锁
时,就可能会发生死锁问题。 - 产生死锁的必要条件:
- 互斥条件:一个资源每次只能被一个进程使用。
- 请求和保持条件:一个进程因请求资源而阻塞时,对方获得的资源保持不放。
- 不剥夺条件:进程已获得资源,在未使用完之前,不能强行剥夺。
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
- 我们只要想办法破坏其中一个条件就可以避免死锁。
Lock锁
- JDK1.5之后出来,提供了更强大的线程同步机制—通过显示定义同步锁对象来实现同步,同步锁使用
Lock
对象充当。 -
java.util.concurrent.locks.lock
接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock
对象加锁,线程开始访问共享资源之前要先获得Lock
对象。 -
ReentrantLock
类实现了Lock
,他拥有与synchronized
相同的并发性和内存语义,在实现线程安全控制中,比较常用的是ReentrantLock
可以显示的加锁,释放锁。
synchronized与lock的区别
-
Lock
是显示锁(手动开启和关闭锁,别忘记关闭锁)synchronized
是隐式锁,出了作用域自动释放。 -
Lock
只有代码快锁,synchronized
有代码块锁和方法锁。 - 使用
Lock
锁,JVM将花费较少的时间来调度线程,性能更好,并且具有更好的扩展性(提供更多的子类) - 优先使用顺序:
Lock
----同步代码块(已经进入了方法体,分配了相应资源)----同步方法(在方法体之外)
生产者消费者问题
- 生产者和消费者共享同一个资源,二者之间互相依赖。互为条件。
- 对于生产者,没有生产产品之前,要通知消费者等待,生产好了之后,要立马通知消费者来取,
- 对于消费者,在消费之后,要通知生产者已经结束消费,需要生产新的产品以供消费。
- 在生产者消费者问题中,仅仅有synchronized是不够的
synchronized
可阻止并发更新同一个共享资源,实现了同步。synchronized
不能用来实现不同线程之间的消息传递(通信)
管程法
信号灯法
线程池
- 经常创建和销毁的,使用量特别大的资源,比如并发情况下的线程,对性能影响很大,
- 提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中,可以避免频繁创建和销毁,实现重复利用,类似生活中的交通工具。
- 使用线程池的好处:
- 提高响应速度(减少了创建线程的时间)。
- 降低资源消耗(重复利用线程池中的线程,不需要每次都创建)
- 便于线程管理:
corePoolSize
:核心池的大小,maximumPoolSize
:最大线程数,KeepAliveTime
:线程没有任务时,最多保持多长时间后会终止。