<>6.死锁

1.死锁的理解:
不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁

2.说明:

* 1出现死锁后,不会出现异常,不会出现提示,只是锁的线程都处于阻塞状态,无法继续
* 2我们使用同步时,要避免出现死锁。
解决方法
专门的算法、原则
尽量减少同步资源的定义
尽量避免嵌套同步

死锁演示:

线程1拿到s1的锁等待s2的锁,线程2拿到s2的锁等待s1的锁…
public static void main(String[] args) { StringBuffer s1 = new StringBuffer();
StringBuffer s2 = new StringBuffer(); new Thread(){ @Override public void run()
{ synchronized (s1){ s1.append("a"); s2.append("1"); try { Thread.sleep(100); }
catch (InterruptedException e) { e.printStackTrace(); } synchronized (s2){ s1.
append("b"); s2.append("2"); System.out.println(s1); System.out.println(s2); } }
} }.start(); new Thread(new Runnable() { @Override public void run() {
synchronized (s2){ s1.append("c"); s2.append("3"); try { Thread.sleep(100); }
catch (InterruptedException e) { e.printStackTrace(); } synchronized (s1){ s1.
append("d"); s2.append("4"); System.out.println(s1); System.out.println(s2); } }
} }).start(); }
主线程拿到A的锁,等待B锁,分线程拿到B锁 等待A锁…
package com.atguigu.java1; //死锁的演示 class A { public synchronized void foo(B b)
{ //同步监视器:A类的对象:a System.out.println("当前线程名: " + Thread.currentThread().getName(
) + " 进入了A实例的foo方法"); // ① // try { // Thread.sleep(200); // } catch
(InterruptedException ex) { // ex.printStackTrace(); // } System.out.println(
"当前线程名: " + Thread.currentThread().getName() + " 企图调用B实例的last方法"); // ③ b.last()
; } public synchronized void last() {//同步监视器:A类的对象:a System.out.println(
"进入了A类的last方法内部"); } } class B { public synchronized void bar(A a) {//同步监视器:b
System.out.println("当前线程名: " + Thread.currentThread().getName() + "
进入了B实例的bar方法"); // ② // try { // Thread.sleep(200); // } catch
(InterruptedException ex) { // ex.printStackTrace(); // } System.out.println(
"当前线程名: " + Thread.currentThread().getName() + " 企图调用A实例的last方法"); // ④ a.last()
; } public synchronized void last() {//同步监视器:b System.out.println(
"进入了B类的last方法内部"); } } public class DeadLock implements Runnable { A a = new A()
; B b = new B(); public void init() { Thread.currentThread().setName("主线程"); //
调用a对象的foo方法 a.foo(b); System.out.println("进入了主线程之后"); } public void run() {
Thread.currentThread().setName("副线程"); // 调用b对象的bar方法 b.bar(a); System.out.
println("进入了副线程之后"); } public static void main(String[] args) { DeadLock dl =
new DeadLock(); new Thread(dl).start(); dl.init(); } }
<>lock

import java.util.concurrent.locks.ReentrantLock; /** * 解决线程安全问题的方式三:Lock锁 ---
JDK5.0新增 * * 1. 面试题:synchronized 与 Lock的异同? * 相同:二者都可以解决线程安全问题 *
不同:synchronized机制在执行完相应的同步代码以后,自动的释放同步监视器 *
Lock需要手动的启动同步(lock()),同时结束同步也需要手动的实现(unlock()) * * 2.优先使用顺序: * Lock 
同步代码块(已经进入了方法体,分配了相应资源)  同步方法(在方法体之外) * * * 面试题:如何解决线程安全问题?有几种方式 * @author
shkstart * @create 2019-02-15 下午 3:38 */ class Window implements Runnable{
private int ticket = 100; //1.实例化ReentrantLock private ReentrantLock lock = new
ReentrantLock(); @Override public void run() { while(true){ try{
//2.调用锁定方法lock() lock.lock(); if(ticket > 0){ try { Thread.sleep(100); } catch (
InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.
currentThread().getName() + ":售票,票号为:" + ticket); ticket--; }else{ break; } }
finally { //3.调用解锁方法:unlock() lock.unlock(); } } } } public class LockTest {
public static void main(String[] args) { Window w = new Window(); Thread t1 =
new Thread(w); Thread t2 = new Thread(w); Thread t3 = new Thread(w); t1.setName(
"窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t1.start(); t2.start(); t3.start()
; } }
synchronized与Lock的对比

* Lock是显式锁(手动开启和关闭锁,别忘记关闭锁),synchronized是
隐式锁,出了作用域自动释放
* Lock只 有代码块锁,synchronized有 代码块锁和方法锁
* 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有
更好的扩展性(提供更多的子类)
优先使用顺序:
Lock→同步代码块(已经进入了方法体,分配了相应资源) >同步方法
(在方法体之外)

技术
下载桌面版
GitHub
Gitee
SourceForge
百度网盘(提取码:draw)
云服务器优惠
华为云优惠券
腾讯云优惠券
阿里云优惠券
Vultr优惠券
站点信息
问题反馈
邮箱:[email protected]
吐槽一下
QQ群:766591547
关注微信