多线程锁

Synchronized锁的八种情况

以一个手机类为例,包含两个synchronized方法和一个普通方法。

public class Phone {
public synchronized void sendSMS() throws InterruptedException {
System.out.println("-----send SMS-----");
} public synchronized void sendEmail() {
System.out.println("-----send email-----");
} public void getHello() {
System.out.println("-----get hello-----");
}
}
  • 1 标准访问
    public static void main(String[] args) {
Phone phone = new Phone();
new Thread(() -> {
phone.sendSMS();
}).start(); new Thread(() -> {
phone.sendEmail();
}).start();
}
-----send SMS-----
-----send email-----
  • 2 短信方法设置4s停止
public class Phone {
public synchronized void sendSMS() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("-----send SMS-----");
} public synchronized void sendEmail() {
System.out.println("-----send email-----");
} public void getHello() {
System.out.println("-----get hello-----");
}
}

-----send SMS-----

-----send email-----

会先等待四秒,短信发送结束才会发送邮件

  • 3 短信停止四秒,同时运行getHello
public class Lock_8 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(() -> {
phone.sendSMS();
}).start(); new Thread(() -> {
phone.getHello();
}).start();
}
}

-----get hello-----

4s。。。

-----send SMS-----

  • 4 两部手机,一部邮件另一部短信
public static void main(String[] args) {
Phone phone = new Phone();
Phone phone2 = new Phone();
new Thread(() -> {
phone.sendSMS();
}).start(); new Thread(() -> {
phone2.sendEmail();
}).start();
}

-----send email-----

4s...

-----send SMS-----

  • 5 两个静态方法,一部手机,先打印邮件还是短信(短信停4s,然后邮件)
  • 6 两个静态方法,两部手机,先打印邮件还是短信(短信停4s,然后邮件)
  • 7 一个静态短信方法,一个邮件方法,1部手机(先邮件,停4s短信)
  • 8 一个静态短信方法,一个邮件方法,2部手机(先邮件,停4s短信)

总结

  • synchronized加在普通方法上,是对this进行加锁,作用范围为当前实例对象
  • synchronized加在静态方法上,是对类的类加载的Class对象加锁,因此作用范围是全部的实例对象

公平锁和非公平锁

当锁被一个线程释放的时候,其他线程抢占锁的机会是否是公平的,分为公平锁和非公平锁。如之前卖票的例子,导致ABC卖票全被A卖了:

  • 公平锁可以防止线程饥饿,但是效率低
A sale 1 ticket, there are 29 tickets left
A sale 1 ticket, there are 28 tickets left
A sale 1 ticket, there are 27 tickets left
A sale 1 ticket, there are 26 tickets left
A sale 1 ticket, there are 25 tickets left
A sale 1 ticket, there are 24 tickets left
A sale 1 ticket, there are 23 tickets left
A sale 1 ticket, there are 22 tickets left
... Process finished with exit code 0

通过ReetranLock构造器设置公平锁

lock = new ReentrantLock(true);
A sale 1 ticket, there are 29 tickets left
B sale 1 ticket, there are 28 tickets left
C sale 1 ticket, there are 27 tickets left
A sale 1 ticket, there are 26 tickets left
B sale 1 ticket, there are 25 tickets left
C sale 1 ticket, there are 24 tickets left
A sale 1 ticket, there are 23 tickets left
B sale 1 ticket, there are 22 tickets left
C sale 1 ticket, there are 21 tickets left

可重入锁

可重入锁:可以重复使用的锁,即某个线程已经获得了某个锁,再次获取锁而不会出现死锁,可重入锁有:

  • synchronized
  • ReentrantLock:ReentrantLock 和 synchronized 不一样,需要手动释放锁,所以使用 ReentrantLock的时候一定要手动释放锁,并且加锁次数和释放次数要一样
synchronized
public static void main(String[] args) {
var obj = new Object();
new Thread(() -> {
synchronized (obj) {
System.out.println("外层");
synchronized (obj) {
System.out.println("中层");
synchronized (obj) {
System.out.println("内层");
}
}
}
}).start();
}

可重入锁又称为递归锁,能够实现同步方法的递归调用而不产生死锁

    static synchronized void add() {
add();
}
public static void main(String[] args) {
new Thread(ThreadDemo4::add).start();
}
Lock
class ShareSource {
private final Lock lock = new ReentrantLock();
public void lockTest() {
lock.lock();
System.out.println("waiceng");
lock.lock();
System.out.println("zhongceng");
lock.lock();
System.out.println("neiceng");
lock.unlock();
lock.unlock();
}
} public class ThreadDemo4 { public static void main(String[] args) {
ShareSource shareSource = new ShareSource();
new Thread(shareSource::lockTest).start();
new Thread(shareSource::lockTest).start();
}
}

Lock不会自动释放锁,上锁和解锁不对应的话会导致死锁的发生,如这里的第二个线程就一直执行不了

死锁

def:两个或两个以上的线程在执行过程中,由于竞争资源而造成的相互等待的现象,如果没有外力作用,则会一直等待下去。

死锁产生的原因

  1. 竞争资源
  2. 进程间推进顺序非法
  3. 资源分配不当
public static void main(String[] args) {
var a = new Object();
var b = new Object(); new Thread(() -> {
synchronized (a) {
System.out.println("已获取锁A,尝试获取锁B");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b) {
System.out.println("已获取锁B");
}
}
}).start(); new Thread(() -> {
synchronized (b) {
System.out.println("已获取锁B,尝试获取锁A");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (a) {
System.out.println("已获取锁A");
}
}
}).start();
}
检查死锁
  1. jsp:查看系统中运行的java进程
  2. jstack:追踪java进程的堆栈情况
"Thread-0":
at com.hikaru.juc.lock.DeadLockDemo.lambda$main$0(DeadLockDemo.java:19)
- waiting to lock <0x0000000711818d28> (a java.lang.Object)
- locked <0x0000000711818d18> (a java.lang.Object)
at com.hikaru.juc.lock.DeadLockDemo$$Lambda$14/0x00000008010031f0.run(Unknown Source)
at java.lang.Thread.run(java.base@19.0.2/Thread.java:1589)
"Thread-1":
at com.hikaru.juc.lock.DeadLockDemo.lambda$main$1(DeadLockDemo.java:33)
- waiting to lock <0x0000000711818d18> (a java.lang.Object)
- locked <0x0000000711818d28> (a java.lang.Object)
at com.hikaru.juc.lock.DeadLockDemo$$Lambda$15/0x0000000801003400.run(Unknown Source)
at java.lang.Thread.run(java.base@19.0.2/Thread.java:1589) Found 1 deadlock.

JUC(四)多线程锁的更多相关文章

  1. JUC之多线程锁问题

    多线程锁 8种问题锁状态: 该部分全部围绕的是以下内容并结合相应的例子:synchronized实现同步的基础:Java中每个对象都可以作为锁. 具体表现为以下三种形式:(之前只是简单的了解) 对于普 ...

  2. Java并发编程(3) JUC中的锁

    一 前言 前面已经说到JUC中的锁主要是基于AQS实现,而AQS(AQS的内部结构 .AQS的设计与实现)在前面已经简单介绍过了.今天记录下JUC包下的锁是怎么基于AQS上实现的 二 同步锁 同步锁不 ...

  3. Python多线程锁

    [Python之旅]第六篇(四):Python多线程锁   python lock 多线程 多线程使用方法 多线程锁 摘要:   在多线程程序执行过程中,为什么需要给一些线程加锁以及如何加锁,下面就来 ...

  4. java 并发多线程 锁的分类概念介绍 多线程下篇(二)

    接下来对锁的概念再次进行深入的介绍 之前反复的提到锁,通常的理解就是,锁---互斥---同步---阻塞 其实这是常用的独占锁(排它锁)的概念,也是一种简单粗暴的解决方案 抗战电影中,经常出现为了阻止日 ...

  5. Java多线程--锁的优化

    Java多线程--锁的优化 提高锁的性能 减少锁的持有时间 一个线程如果持有锁太长时间,其他线程就必须等待相应的时间,如果有多个线程都在等待该资源,整体性能必然下降.所有有必要减少单个线程持有锁的时间 ...

  6. synchronized与static synchronized 的差别、synchronized在JVM底层的实现原理及Java多线程锁理解

    本Blog分为例如以下部分: 第一部分:synchronized与static synchronized 的差别 第二部分:JVM底层又是怎样实现synchronized的 第三部分:Java多线程锁 ...

  7. Java高并发与多线程(四)-----锁

    今天,我们开始Java高并发与多线程的第四篇,锁. 之前的三篇,基本上都是在讲一些概念性和基础性的东西,东西有点零碎,但是像文科科目一样,记住就好了. 但是本篇是高并发里面真正的基石,需要大量的理解和 ...

  8. java并发编程(四)----(JUC)Lock锁初探

    首先我们来回忆一下上一节讲过的synchronized关键字,该关键字用于给代码段或方法加锁,使得某一时刻它修饰的方法或代码段只能被一个线程访问.那么试想,当我们遇到这样的情况:当synchroniz ...

  9. 细说.NET中的多线程 (四 使用锁进行同步)

    通过锁来实现同步 排它锁主要用来保证,在一段时间内,只有一个线程可以访问某一段代码.两种主要类型的排它锁是lock和Mutex.Lock和Mutex相比构造起来更方便,运行的也更快.但是Mutex可以 ...

  10. Java - "JUC" ReentrantLock获取锁

    [Java并发编程实战]-----“J.U.C”:ReentrantLock之一简介 ReentrantLock介绍 ReentrantLock是一个可重入的互斥锁,又被称为“独占锁”. 顾名思义,R ...

随机推荐

  1. eclipse project is missing required java project

    eclipse project is missing required java project eclipse版本: 2022-03 这情况就是maven包出了问题 具体的说不上 看我的解决方法: ...

  2. OSIDP-并发:死锁和饥饿-06

    死锁原理 死锁:一组相互竞争系统资源或者进行通信的进程间"永久"阻塞的现象. 资源分为两类:可重用资源和可消耗资源. 可重用资源:一次只能被一个进程使用且不会被耗尽的资源.如处理器 ...

  3. Bad Request - Invalid Hostname HTTP Error 400. The request hostname is invalid.

    VS 调试 显示 如下错误 解决办法: 1 打开调试运行中的 IIS Express 2 点击其中一条记录 3  点击配置 4 找到对应项目站点 .添加 <binding protocol=&q ...

  4. python高阶编程(一)

    1.生成器 通过列表⽣成式,我们可以直接创建⼀个列表.但是,受到内存限制,列表容量肯定是有限的.⽽且,创建⼀个包 含100万个元素的列表,不仅占⽤很⼤的存储空间,如果我们仅仅需要访问前⾯⼏个元素,那后 ...

  5. python3安装turtle失败问题

    失败截图: 解决办法: 1.下载turtle-0.0.2 2.解压文件夹到指定目录 3.打开setup.py找到第四十行修改 4.打开cmd进入turtle-0.0.2所在文件夹的上一层文件夹,执行p ...

  6. Delphi中IdHttp调用接口,返回值乱码

    --------开发环境是Delphi XE10-------- 这里要说的是BUG问题, var respStream : TStringStream; respStream.DataString有 ...

  7. weblogic session timed out

    How to Configure Session Timeout in Weblogic Server (WLS) ?

  8. Ubuntu 22.04 安装 VMWare 16.2.3 后无法启动

    异常日志: 2022-06-13T03:49:56.019Z In(05) host-29676 In file included from /tmp/modconfig-XR2GVI/vmmon-o ...

  9. C# DataTable操作,转载

    DataTable 排序   DataRow[] rows = dataTable1.Select("", "ord asc");   DataTable t ...

  10. ssh基于主机名访问

    登录一台服务器我们可以用ssh user@IP这种方式 还有一种快捷的方式,就是基于主机名访问,这需要先配置 /etc/hosts文件 假如我们又两台主机 192.168.75.131/165 分别为 ...