Java 中线程同步机制synchronized,互斥锁,死锁,释放锁的详解
Posted 路宇
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 中线程同步机制synchronized,互斥锁,死锁,释放锁的详解相关的知识,希望对你有一定的参考价值。
博主前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住也分享一下给大家,
👉点击跳转到网站
一、线程同步机制synchronized的理解
二、synchronized的具体使用
下面可以通过同步机制,解决多线程卖票,出现的超卖问题,代码如下
public class SellTicket
public static void main(String[] args)
// SellTicket01 sellTicket01 = new SellTicket01();
// SellTicket01 sellTicket02 = new SellTicket01();
// SellTicket01 sellTicket03 = new SellTicket01();
//
// //这里会出现超卖现象
// sellTicket01.start();//启动售票线程
// sellTicket02.start();//启动售票线程
// sellTicket03.start();//启动售票线程
/*
输出结果:
窗口 Thread-0 售出一张票剩余票数=2
窗口 Thread-1 售出一张票剩余票数=-1
售票结束
窗口 Thread-0 售出一张票剩余票数=-2
售票结束
窗口 Thread-2 售出一张票剩余票数=0
售票结束
*/
// System.out.println("----使用实现接口的方式来售票----");
// SellTicket02 sellTicket02 = new SellTicket02();
// new Thread(sellTicket02).start();//第1个线程-窗口
// new Thread(sellTicket02).start();//第2个线程-窗口
// new Thread(sellTicket02).start();//第3个线程-窗口
/*
输出结果
窗口 Thread-0 售出一张票剩余票数=2
窗口 Thread-2 售出一张票剩余票数=1
窗口 Thread-2 售出一张票剩余票数=0
售票结束
窗口 Thread-0 售出一张票剩余票数=-1
售票结束
窗口 Thread-1 售出一张票剩余票数=-2
售票结束
*/
System.out.println("----使用线程同步的方式来解决超卖票的情况----");
SellTicket03 sellTicket03 = new SellTicket03();
new Thread(sellTicket03).start();//第1个线程-窗口
new Thread(sellTicket03).start();//第2个线程-窗口
new Thread(sellTicket03).start();//第3个线程-窗口
/*
窗口 Thread-0 售出一张票剩余票数=6
窗口 Thread-0 售出一张票剩余票数=5
窗口 Thread-0 售出一张票剩余票数=4
窗口 Thread-0 售出一张票剩余票数=3
窗口 Thread-0 售出一张票剩余票数=2
窗口 Thread-0 售出一张票剩余票数=1
窗口 Thread-2 售出一张票剩余票数=0
售票结束...
售票结束...
售票结束...
*/
//使用Thread方式
class SellTicket01 extends Thread
private static int ticketNum = 100;//让多个线程共享
@Override
public void run()
while (true)
//在判断这个条件的时候,三个线程会同时进来 当ticketNum等于1时,
//三个线程都进来了,会出现超卖的情况
if (ticketNum <= 0)
System.out.println("售票结束");
break;
//休眠50毫秒,模拟
try
Thread.sleep(50);
catch (InterruptedException e)
e.printStackTrace();
System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
+ "剩余票数=" + (--ticketNum));
//实现接口方式
class SellTicket02 implements Runnable
private int ticketNum = 100;
@Override
public void run()
while (true)
if (ticketNum <= 0)
System.out.println("售票结束");
break;
//休眠50毫秒,模拟
try
Thread.sleep(50);
catch (InterruptedException e)
e.printStackTrace();
System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
+ "剩余票数=" + (--ticketNum));
//实现接口方式,使用synchronized实现线程同步
class SellTicket03 implements Runnable
private int ticketNum = 100;
private boolean loop = true;
public synchronized void sell() //同步方法,在同一时刻,只能有一个线程来执行sell方法
if (ticketNum <= 0)
System.out.println("售票结束...");
loop = false;
return;
//休眠50毫秒,模拟
try
Thread.sleep(50);
catch (InterruptedException e)
e.printStackTrace();
System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
+ "剩余票数=" + (--ticketNum));
@Override
public void run()
while (loop)
sell();//sell方法是一个同步方法
分析同步原理
三、互斥锁的介绍
下面演示在代码块中加锁,和方法上加锁,还是以上面的多线程卖票为例
//实现接口方式,使用synchronized实现线程同步
class SellTicket03 implements Runnable
private int ticketNum = 100;
private boolean loop = true;
Object object = new Object();//也可以用同一个对象,比如object,因为是三个线程共享一个object对象,满足三个线程共享一个对象
//同步方法(静态的)的锁为当前类本身
//1.public synchronized static void m1()锁 是加在SellTicket03.class
//2.如果在静态方法中,实现一个同步代码块
/*
synchronized (SellTicket03.class)
System.out.println("m2");
*/
public synchronized static void m1()
public static void m2()
synchronized (SellTicket03.class)
System.out.println("m2");
//1. public synchronized void sell() 就是一个同步方法
//2.也可以在代码块上写synchronized ,同步代码块,互斥锁还是在this对象
public /*synchronized*/ void sell() //同步方法,在同一时刻,只能有一个线程来执行sell方法
synchronized (/*this*/object)
if (ticketNum <= 0)
System.out.println("售票结束...");
loop = false;
return;
//休眠50毫秒,模拟
try
Thread.sleep(50);
catch (InterruptedException e)
e.printStackTrace();
System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
+ "剩余票数=" + (--ticketNum));
@Override
public void run()
while (loop)
sell();//sell方法是一个同步方法
互斥锁的注意细节如下
四、线程的死锁
public class DeadLock_
public static void main(String[] args)
//模拟死锁现象
DeadLockDemo A = new DeadLockDemo(true);
A.setName("A线程");
DeadLockDemo B = new DeadLockDemo(false);
B.setName("B线程");
A.start();
B.start();
//线程
class DeadLockDemo extends Thread
static Object o1 = new Object();//保证多线程,共享一个对象,这里使用static
static Object o2 = new Object();
boolean flag;
public DeadLockDemo(boolean flag)
this.flag = flag;
@Override
public void run()
//下面业务逻辑分析
//1.如果flag为true,线程A就会先得到/持有 o1 对象锁,然后尝试去获取o2对象锁
//2.如果线程A 得不到o2对象锁,就会Blocked
//3.如果flag为false,线程B就会先得到/持有 o2 对象锁,然后尝试去获取o1对象锁
//2.如果线程B 得不到o1对象锁,就会Blocked
if (flag)
synchronized (o1) //对象互斥锁,下面是同步代码
System.out.println(Thread.currentThread().getName() + " 进入1");
synchronized (o2) //这里获得li对象的监视权
System.out.println(Thread.currentThread().getName() + "进入2");
else
synchronized (o2)
System.out.println(Thread.currentThread().getName() + " 进入3");
synchronized (o1) //这里获得li对象的监视权
System.out.println(Thread.currentThread().getName() + "进入4");
输出结果
B线程 进入3
A线程 进入1
之后就卡在这里了,写代码时一定要避免
下面操作会释放锁
下面操作不会释放锁
线程相关的练习题如下
代码如下
public class HomeWork01
public static void main(String[] args)
A a = new A();
a.start();
B b = new B(a);
b.start();
class A extends Thread
private boolean loop = true;
public void setLoop(boolean loop)
this.loop = loop;
@Override
public void run()
while (loop)
System.out.println((int) (Math.random() * 100 + 1));
try
Thread.sleep(1000);
catch (InterruptedException e)
e.printStackTrace();
System.out.println("a线程退出...");
class B extends Thread
private A a;
public B(A a) //构造器中,传入A类对象
this.a = a;
@Override
public void run()
while (true)
//接收到用户的输入
System.out.println("请输入命令");
Scanner scanner = new Scanner(System.in);
char c = scanner.next().toUpperCase().charAt(0);
if (c == 'Q')
//以通知的方式结束A线程
a.setLoop(false);
break;
System.out.println("b线程退出...");
输出结果如下
85
请输入命令
8
41
79
81
75
41
29
Q
b线程退出...
a线程退出...
练习题二
代码如下
public class HomeWork02
public static void main(String[] args)
Card card = new Card();
new Thread(card).start();
new Thread(card).start();
//编程取款的线程
//1.因为这里涉及到多个线程共享线程资源,所以我们使用实现Runnable方式
class Card implements Runnable
private boolean loop = true;
private int balance = 10000;
@Override
public void run()
while (loop)
//解读:
//1.这里使用synchronized实现了线程同步
//2.当多个线程执行到这里时,就会去争夺this对象锁
//3.哪个对象争夺到(获取)this对象锁,就执行synchronized代码块,执行完成后,会释放this对象锁
//4.争夺不到this对象锁,就blocked,准备继续争夺
//5.this对象锁 是非公平锁
synchronized (this)
if (balance < 1000)
System.out.println("余额不足..");
loop = false;
return;
System.out.println(Thread.currentThread().getName() + " 取出1000 剩余余额为:" + (balance -= 1000));
try
Thread.sleep(1000);
catch (InterruptedException e)
e.printStackTrace();
输出结果如下
Thread-0 取出1000 剩余余额为:9000
Thread-1 取出1000 剩余余额为:8000
Thread-1 取出1000 剩余余额为:7000
Thread-0 取出1000 剩余余额为:6000
Thread-1 取出1000 剩余余额为:5000
Thread-0 取出1000 剩余余额为:4000
Thread-1 取出1000 剩余余额为:3000
Thread-0 取出1000 剩余余额为:2000
Thread-1 取出1000 剩余余额为:1000
Thread-0 取出1000 剩余余额为:0
余额不足..
余额不足..
以上是关于Java 中线程同步机制synchronized,互斥锁,死锁,释放锁的详解的主要内容,如果未能解决你的问题,请参考以下文章
Java 中线程同步机制synchronized,互斥锁,死锁,释放锁的详解
Java 中线程同步机制synchronized,互斥锁,死锁,释放锁的详解