首页 > 其他分享 >JUC(四)多线程锁

JUC(四)多线程锁

时间:2023-03-09 19:58:58浏览次数:41  
标签:JUC synchronized Thread ----- new ticket 多线程 public

目录

多线程锁

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([email protected]/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([email protected]/Thread.java:1589)

Found 1 deadlock.

标签:JUC,synchronized,Thread,-----,new,ticket,多线程,public
From: https://www.cnblogs.com/tod4/p/17201190.html

相关文章

  • JUC(七)分支合并框架
    JUC分支合并框架简介Fork/Join可以将一个大的任务拆分成多个子任务进行并行处理,最后将子任务的结果合并称为最终的计算结果。Fork:负责将任务拆分Join:合并拆分任务For......
  • JUC(五)Callable
    Callable接口创建线程的几种方式继承Thread类实现Runnable接口通过Callable接口线程池使用Runnable接口无法获取到线程返回的结果,因此在jdk1.5后java提供了Callabl......
  • JUC(八)ThreadLocal
    ThreadLocal简介ThreadLocal提供局部线程变量,这个变量与普通的变量不同,每个线程在访问ThreadLocal实例的时候,(通过get或者set方法)都有自己的、独立初始化变量副本。Threa......
  • Linux高并发服务器之Linux多线程开发
    本文源自C++高薪面试项目的学习笔记,主要记录Liunx多线程的学习,主要知识点是线程概述等基础概念以外,还有线程相关Liunx系统函数以及对应练手代码,除此之外还有线程同步问题的......
  • JAVA多线程处理大量数据
    背景说明:要对服务器上一个目录进行全量文件读取,采用传统的单线程性能较差,耗时严重。1、多线程执行类--FileThreadUtils.javaimportcn.hutool.core.collection.CollUtil......
  • python单例模式处理多线程问题
    #单例模式处理多线程的问题importthreadingimporttimeclassSingle:instance=Nonedef__init__(self,name):self.name=namedef__new__(cls,......
  • 多线程的interrut()方法
    java中的interrut方法,主要作用为中断指定线程,该中断并非是直接打断,而是将线程的中断标志设置为1,当线程执行到sleep、wait方法陷入的阻塞状态,则进行中断,抛出interrutExcepti......
  • python 多线程, 多进程, ProcessPoolExecutor. 有关GIL锁的问题实验.
    importtimeimportthreadingfrommultiprocessingimportProcessfromconcurrent.futuresimportProcessPoolExecutordeftime_decorator(func):defwrapper......
  • 多线程设计模式-全面详解(学习总结---从入门到深化)
    目录​​SingleThreadExecution设计模式​​​​机场过安检​​​​ 非线程安全​​​​ 问题分析​​​​首字母相同却未通过检查​​​​为何出现首字母不相同的情况......
  • C# 多线程(Thread和Task)
    C#多线程(Thread和Task)线程(Thread)是进程中的基本执行单元,是操作系统分配CPU时间的基本单位,一个进程可以包含若干个线程,在进程入口执行的第一个线程被视为这个进......