【JUC】一、synchronized关键字与Lock接口

news/2024/5/20 10:05:18 标签: JUC, 并发, Java

文章目录

  • 1、JUC
  • 2、进程与线程
  • 3、并发与并行
  • 4、用户线程和守护线程
  • 5、对象锁和类锁
  • 6、Synchronized关键字
  • 7、synchronized案例
  • 8、Lock接口

JUC_2">1、JUC

JUC,即java.util.concurrent这个处理线程的工具包,始于JDK1.5,其中下有三个包,为:

  • 基础包
  • 原子包
  • 锁包

在这里插入图片描述

2、进程与线程

进程与线程的关系:

  • 进程是一个应用程序(一个进程是一个软件)
  • 线程是一个进程中的执行场景/执行单元。一个进程可以启动多个线程

把进程看作是现实生活中的公司,如京东。线程则可看作是其下的某一个职能部门,负责完成某任务,如开发部门。

举个例子:

DOS窗口运行java HelloWorld,先启动JVM,JVM是一个进程,JVM启动一个主线程调用main方法,同时再启动一个垃圾回收线程来负责看护、回收垃圾。(也就是说Java程序至少两线程并发,main方法对应的主线程+GC)

进程A和进程B的内存关系:

Java中,线程A和线程B,堆内存和方法区内存共享,但栈内存独立,一个线程一个栈。如启动了10个线程,就会有10个栈空间,每个栈和每个栈之间互不干扰,各自执行各自的,这就是多线程并发

举个例子:

🍁Java中的多线程机制,目的就是为了提高程序的处理效率, 如火车站看成是一个进程,则每个售票小窗口就是一个个线程,甲在窗口1买票,乙在窗口2买票,谁也不用等谁 一个个售票窗口就像一个个栈,有自己独立的空间。售票大厅这个共用空间就像堆和方法区

3、并发与并行

先说下串行和并行:

  • 串行模式就是一次只能取一个任务,并执行这个任务,如必须先装完一车柴,才能运送这车柴,只有送到了,才能卸下这车柴。一个步骤完成了,才能进行下一个步骤。
  • 并行模式即可以同时取多个任务,并同时去执行所取得的这些任务

并行和并发,则是:

  • 并发同一时刻,多个线程在访问同一个资源,多个线程对一个点,对应的例子: 春运抢票 电商秒杀

  • 并行:多项工作一起执行,之后再汇总例子,举例就是泡方便面,电水壶烧水,一边撕调料倒入桶中

4、用户线程和守护线程

Java中的线程分两类:

  • 用户自定义的线程,如主线程main线程、或者自定义的其他线程
  • 守护线程:如垃圾回收线程。一般守护线程是一个死循环,所有用户线程结束的时候,守护线程自动结束

写个测试代码:

public static void main(String[] args){

	Thread aa = new Thread( () -> {
		
		System.out.println(Thread.currentThread().getName() + "::" + Thread.currentThread().isDaemon());
		while (true) {
		
		}
	}, "aa");
	aa.setDaemon(true);
	aa.start();
	System.out.println(Thread.currentThread().getName() + " over");
}

可以看到,aa.setDaemon(true)被注释时,aa线程属于用户自定义线程,此时main线程结束以后,自定义的aa线程不受影响,JVM继续存活:

在这里插入图片描述

aa线程被set为守护线程后,则当用户线程都结束时,守护线程自动结束:

在这里插入图片描述

5、对象锁和类锁

锁是控制多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问。一次只能有一个线程获得锁,对共享资源的所有访问都需要首先获得锁。不过,某些锁可能允许对共享资源并发访问,如ReadwriteLock的读取锁。

  • 类锁属于一个类,类似静态变量,多个实例对象对应同一个锁,一个类一把锁
  • 对象锁属于对象实例,类似类属性变量,每一个实例对象,就对应一个锁,100个类A的对象,就有一百个对象锁

6、Synchronized关键字

synchronized是Java关键字,表示一种同步锁,这个关键字:

  • 可修饰代码块,作用范围是大括号中的语句,作用对象是调用这个代码块的对象
synchronized(线程共享对象){//线程同步代码块,即要排队执行的代码块}
  • 可修饰方法,作用范围是整个方法,作用对象是调用这个方法的对象
public synchronized void doSome(){
	//...
}
  • 在实例方法中使用synchronized,表示共享的对象一定是this,并且同步的代码块是整个方法体
  • 在静态方法中使用synchronized,表示找类锁,类锁永远只有1把(对象锁是100个对象就有100个对象锁)

7、synchronized案例

多线程编程的步骤

  • 步骤一:创建(将来被共享的)资源类,创建属性和操作方法
  • 步骤二:在资源类的操作方法中进行:判断、干活儿、通知
  • 步骤三:创建多线程调用资源类的方法
  • 步骤四:防止虚假唤醒现象

模拟三个售票员同时对外出售30张票,三个售票员,即三个线程,资源类就是票类,资源类的属性是票的数量:

//资源类
class Ticket{

    private Integer number = 30;

    public synchronized void sale(){
        if(number > 0 ){
            System.out.println(Thread.currentThread().getName() + ": 卖出票,剩余" + number--);
        }
    }
}

开三个线程,调用资源类中的方法:

public class SaleTicket {

    public static void main(String[] args) {
    	//多个线程共用这个资源对象
        Ticket ticket = new Ticket();
        new Thread(() -> {
            for(int i = 0 ; i < 40; i++ ){
                ticket.sale();
            }
        },"AA").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i = 0 ; i < 40; i++ ){
                    ticket.sale();
                }
            }
        },"BB").start();
        Thread cc = new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        }, "CC");
        cc.setPriority(Thread.MAX_PRIORITY);
        cc.start();
    }


}


在这里插入图片描述

8、Lock接口

API文档:

https://tool.oschina.net/apidocs/apidoc?api=jdk-zh

Lock接口比synchronized更灵活,其实现类有:

  • ReentrantLock
  • ReentrantReadWriteLock.ReadLock
  • ReentrantReadWriteLock.WriteLock

ReentrantLock即可重入锁,类比排队上厕所,进门后锁门,用完后解锁,下个人继续上锁,用完解锁。

class X {
   private final ReentrantLock lock = new ReentrantLock();
   // ...

   public void m() { 
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock()
     }
   }
 }

Lock接口比synchronized的对比:

  • Lock是一个接口,有对应的实现类,而synchronized是Java关键字
  • synchronized不需要用户去手动释放锁,synchronized代码块或者方法执行结束或者发生异常时,系统会自动让线程释放锁,而Lock需要开发者手动释放锁
  • Lock可以让等待锁的线程响应终端,而synchronized不行,等待的线程会一直等待下去
  • Lock可以直到有没有成功获取锁,而synchronized不行
  • Lock可以提到多个线程进行读操作的效率
  • 大量线程同时竞争激烈时,Lock性能远胜synchronized

用Lock实现上篇synchronized实现的卖票例子:

//资源类
class LTicket{

    private Integer number = 30;

    private final ReentrantLock lock = new ReentrantLock();

    public void sale(){
        //上锁
        lock.lock();
        try {
            if( number > 0 ){
                System.out.println(Thread.currentThread().getName() + ": 卖出票,剩余" + number--);
            }

        } finally {
            //释放锁写finally语句中,防止上面发生异常导致锁未释放
            lock.unlock();
        }
    }
}

创建共享资源类对象,开多个线程调用资源类的方法:

public class LSaleTicket {

    public static void main(String[] args) {
        LTicket ticket = new LTicket();
        new Thread(() -> {
            for(int i = 0 ; i < 40; i++ ){
                ticket.sale();
            }
        },"AA").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i = 0 ; i < 40; i++ ){
                    ticket.sale();
                }
            }
        },"BB").start();
        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        }, "CC").start();
    }
}


http://www.niftyadmin.cn/n/5174137.html

相关文章

【C++笔记】二叉搜索树的模拟实现

【C笔记】二叉搜索树的模拟实现 一、二叉搜索树的概念二、二叉搜索树的模拟实现2.0、定义二叉树节点2.1、非递归接口实现2.1.1、插入2.1.2、查找2.1.3、删除 2.2、递归接口实现2.2.1、插入2.2.2、查找2.2.3、删除 三、升级为K-V模型 一、二叉搜索树的概念 二叉搜索树的概念&am…

网康NS-ASG安全网关任意文件读取

此文件没有对身份进行校验即可下载任意文件 构造payload访问漏洞url&#xff1a; ​​/admin/cert_download.php?filegjxbstxdt.txt&certfile../../../../../../../../etc/passwd漏洞证明&#xff1a; 文笔生疏&#xff0c;措辞浅薄&#xff0c;望各位大佬不吝赐教&…

轻量级服务器的特点,你是否真的需要

一、概念 大家都知道云服务器是在云计算环境中运行的虚拟&#xff08;而非物理&#xff09;服务器&#xff0c;可由无限用户按需访问。通过使用虚拟化软件&#xff08;称为虚拟机监控程序&#xff09;将物理服务器划分为多个虚拟服务器来创建的。虚拟机监控程序将服务器的处理…

洛谷 NOIP 2023 模拟赛 种树

洛谷 NOIP 2023 模拟赛 种树 题目大意 路边有 n n n棵树&#xff0c;第 i i i棵树的高度为 a i a_i ai​。 定义这棵树的宽度为它高度的正因数个数&#xff0c;这些树能覆盖的距离为它们宽度的乘积。 你有 w w w个单位的化肥&#xff0c;你可以施若干次肥&#xff0c;每次你…

两个序列(数论)

两个序列 Problem:B Time Limit:1000ms Memory Limit:65535K Description Gugu 有两个长度无限长的序列A,BA0a^0/0!,A1a^1/1!,A2a^2/2!,A3a^3/3!…. B00, B1b^1/1!,B20,B3b^3/3!,B40, B5b^5/5! … Douge 看到这道这两个序列很觉得很麻烦&#xff0c;所以他想到一个好点子&…

如何在 Python 中执行 MySQL 结果限制和分页查询

Python MySQL 限制结果 限制结果数量 示例 1: 获取您自己的 Python 服务器 选择 “customers” 表中的前 5 条记录&#xff1a; import mysql.connectormydb mysql.connector.connect(host"localhost",user"您的用户名",password"您的密码"…

针对CSP-J/S的每日一练(5)

一、审题 题目描述 珂朵莉有一个正整数数列 { a n } \{a_n\} {an​}&#xff0c;对于所有的 i ≥ 1 i\geq 1 i≥1&#xff0c; a i 1 a i i 1 a_{i1}a_{i}\times i1 ai1​ai​i1。 现在她定义了一个新的数列 { b n } \{b_n\} {bn​}&#xff0c;对于所有的 i ≥ 1 i\g…

OpenShift 4 - 对 OpenShift 的 etcd 数据库加密

《OpenShift / RHEL / DevSecOps 汇总目录》 说明&#xff1a;本文已经在 OpenShift 4.14 的环境中验证 文章目录 加密 etcd 数据库验证加密的 etcd 数据库解密 etcd 数据库 加密 etcd 数据库 OpenShift 对 etcd 数据库加密时只加密值&#xff0c;而不加密键。而资源类型、命…