JUC 并发进阶学习(一)

news2024/9/25 3:26:35

该学习笔记是本人依据相关的学习视频整体汇总,相关的视频学习可以自己去搜看看。

【狂神说Java】JUC并发编程最新版通俗易懂_哔哩哔哩_bilibili

一、什么是JUC

从中就可以看出JUC,实质就是三个包,后面晖详细说明三个包下各个类功能。

java.util.concurrent 

java.util.concurrent.atomic

java.util.concurrent.locks

二、线程和进程

1.区别

  进程:就是一个程序,比如QQ、音乐、微信;

  线程:一个进程可以包含多个线程,至少包含一个线程;

  java默认连个线程:main线程+GC线程;

  线程实现方式:Thread、Runnable、Callable

  2.JAVA实质无法开启线程,而是由底层C++进行开启的,开启的线程源码如下:

public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            // 线程实质开启的位置,看start0()方法如下:
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }


    // 其实调用的就是本地的线程开启方法
    private native void start0();

3.线程的6种状态:来源于Threa种的源码查看

public enum State {
       // 创建
        NEW,

       // 运行
        RUNNABLE,

        // 阻塞
        BLOCKED,

        // 等待,死等
        WAITING,

        // 超时等待
        TIMED_WAITING,

        // 终止
        TERMINATED;
}

4.wait和sleep区别

 1)来自类不同:wait->Object;sleep-> Thread

 2)  锁的释放:wait->释放锁,sleep-> 不释放锁

 3)使用范围:wait-> 同步代码块种,sleep-> 随时

 4)是否需要捕获异常:wait->不需要捕获异常,sleep->需要捕获异常

【补充知识】:常用睡眠的方法,TimeUnit来自java.util.concurrent包
TimeUnit.SECONDS.sleep(2); // 秒
TimeUnit.DAYS.sleep(2);   // 天
TimeUnit.HOURS.sleep(2);  // 小时

5.并发和并行

1、并发(多个线程抢一个资源)

      CPU一核,模拟出多个线程,快速叠替

2、并行(多个人并排行走)

      CPU多核,多个线程可以同时执行,线程池;

3、并发本质

       充分利用CPU资源

【补充知识】:查看服务器的核数

Runtime.getRuntime().availableProcessors();

三、Lock锁(重点)

1.传统的synchronized

package com.project.concurrency.synchronizedStudy_1;

/**
* 售票功能
*/
public class SynchronizedSaleDemo {
    public static void main(String[] args) {
        Tack dataA = new Tack();
        new Thread(()->{
            for (int i = 0; i < 20; i++) {
                dataA.sale();
            }
        },"A").start();

        new Thread(()->{
            for (int i = 0; i < 20; i++) {
                dataA.sale();
            }
        },"B").start();

        new Thread(()->{
            for (int i = 0; i < 20; i++) {
                dataA.sale();
            }
        },"C").start();

        new Thread(()->{
            for (int i = 0; i < 20; i++) {
                dataA.sale();
            }
        },"D").start();
    }
}

class Tack{
    private int number = 60;

    protected synchronized void sale(){
        if(number>0){
            System.out.println(Thread.currentThread().getName()+"卖了第"+(number--)+"张票,还剩"+number+"张票");
        }else {
            System.out.println(Thread.currentThread().getName()+"没有买到票");
        }
    }


}

2.Lock锁使用方式

从JDK种可以查看到对应Lock使用的一些简单描述:

Lock是一个接口,有三个实现类,分别是如下:

  • ReentrantLock 可重入锁 (常用)

  • ReentrantReadWriteLock.ReadLock 读锁 

  • ReentrantReadWriteLock.WriteLock 写锁

1)ReentrantLock  可重入锁,有两个构造方法:

     // 创建非公平锁
     public ReentrantLock() {
        sync = new NonfairSync();
     }
    
    // 根据参数进行选择创建非公平锁还是公平锁
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

 【公平锁】很公平,进行先来后到

 【非公平锁】不公平,可以插队,依据cpu选择执行前后(默认)

 2)ReentrantLock  可重入锁的使用依据举例

使用方式如下:
// 创建锁
Lock l = ...;
// 加锁 
l.lock(); 
try { 
  // 执行业务代码 
} finally { 
  // 释放锁
  l.unlock(); 
} 



举例:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 采用Lock 实现买票
 */
public class LockDemo {
    public static void main(String[] args) {
        DataA dataA = new DataA();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                dataA.increamNumber();
            }
        },"A").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                dataA.decrement();
            }
        },"B").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                dataA.increamNumberC();
            }
        },"C").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                dataA.decrementD();
            }
        },"D").start();
    }
}

class DataA{
    private int number = 0;
    Lock lock = new ReentrantLock();
   
    public  void increamNumber()  {
        // 加锁
        lock.lock();
        try {
            if(number>0){
                number--;
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            // 解锁
            lock.unlock();
        }
    }

}

3)synchronized与Lock区别

1.synchronized是关键字,Lock是类接口;

2.synchronized无法获取锁的状态,Lock可以查看所得状态;

3.synchronized会自动释放锁,Lock必须手动释放锁,否则会死锁;

4.synchronized(线程一,阻塞,线程二就会死死的等),Lock就不一定等了;

5.synchronized可重入锁,不可中断,非公平的,Lock 可重入锁,可中断, 可选公平或是非公平;

6.synchronized适合锁少量代码,Lock适合大量代码同步问题。

【可重入锁】可重入是指一个线程如果获取了锁,那么它就是锁的主人,那么它可以再次获取这把锁,这种就是理解为重入,简而言之,可以重复获取同一把锁,不会造成阻塞死锁。例如:

    @Test
    public void testRepeatLock() {
        ReentrantLock reentrantLock = new ReentrantLock();
        // 第一次获取锁
        reentrantLock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " first get lock");
            // 再次获取锁
            tryAgainLock(reentrantLock);
        }finally {
            reentrantLock.unlock();
        }
    }
    public void tryAgainLock(ReentrantLock reentrantLock) {
        // 第2次获取锁
        reentrantLock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " second get lock");
        }finally {
            reentrantLock.unlock();
        }
    }

四、生产者消费者问题实现

需求:实现线程一:变量+1,线程二:变量-1,两个线程交替工作

package com.project.concurrency.lockStudy_2;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 采用Lock 实现生产者、消费者
 */
public class LockDemo {
    public static void main(String[] args) {
        DataA dataA = new DataA();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                dataA.increamNumber();
            }
        },"A").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                dataA.decrement();
            }
        },"B").start();
    }
}

class DataA{
    private int number = 0;
    Lock lock = new ReentrantLock();
    Condition conditionA = lock.newCondition();
    Condition conditionB = lock.newCondition();
    // +1,采用while的就是避免唤醒之后没有判断就立马执行下一行
    public  void increamNumber()  {
        // 加锁
        lock.lock();
        try {
            while (number!=0){
                // 等待
                conditionA.await();
            }
            number = number+1;
            System.out.println(Thread.currentThread().getName() + "=>" + number);
            // 唤醒conditionB,也可以唤醒全部,condition.signalAll
            conditionB.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            // 解锁
            lock.unlock();
        }

    }

    // -1
    public  void decrement()  {
        lock.lock();
        try {
            while (number!=1){
                // 等待
                conditionB.await();
            }
            number = number-1;
            System.out.println(Thread.currentThread().getName() + "=>" + number);
            // 唤醒某个线程
            conditionA.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            // 解锁
            lock.unlock();
        }
    }



}

五、锁是什么,锁的对象是什么?8锁问题

1.synchronized修饰普通方法:锁的是方法的调用者(对象);

2.synchronized修饰静态方法:锁的是方法归属的类(Class);

3.synchronized修饰代码快synchronized(this),锁得是对象;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/130179.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

程序员的测试课

git项目地址&#xff1a;GitHub - dreamhead/geektime-todo: Geektime Todo is a demo todo project for Geektime column. 1、实现一个Todo应用 设计规范 1、对于输入参数的检测&#xff0c;由入口部分代码进行处理。如空字符串。 2、Repository 的问题以运行时异常 的形式抛…

Django+Celery+Flower实现异步和定时任务及其监控告警

用Django框架进行web开发非常的快捷方便&#xff0c;但Django框架请求/响应是同步的。但我们在实际项目中经常会碰到一些耗时的不能立即返回请求结果任务如&#xff1a;数据爬取、发邮件等&#xff0c;如果常时间等待对用户体验不是很好&#xff0c;在这种情况下就需要实现异步…

SOFA Weekly|2023 我们一起加油、本周 Contributor QA

SOFA WEEKLY | 每周精选 筛选每周精华问答&#xff0c;同步开源进展欢迎留言互动&#xff5e;SOFAStack&#xff08;Scalable Open Financial Architecture Stack&#xff09;是蚂蚁集团自主研发的金融级云原生架构&#xff0c;包含了构建金融级云原生架构所需的各个组件&#…

RocketMQ 搭建

目录 1、什么是MQ&#xff1f;为什么要用MQ&#xff1f; 2、MQ的优缺点 3、几大MQ产品特点比较 4.RocketMQ在Windows的启动 1.下载RocketMQ 4.7.1版本 2.解压到本地磁盘并配置好JAVA_HOME和ROCKETMQ_HOME 3.修改runserver.cmd 4.启动server 5.修改runbroker.cmd 6.启动…

ROS2 基础概念 服务

ROS2 基础概念 服务1. Services2. 服务类型3. 查找服务4. 服务请求1. Services 服务基于 请求-应答 模型&#xff0c;而不是话题的 发布-订阅 模型 虽然话题允许节点订阅数据流并获得持续更新&#xff0c;但服务 仅在客户端专门调用时提供数据 还是启动海龟及其遥控节点为例&…

[标准库]STM32F103R8T6 点灯以及按键扫描

刚开始学32的时候&#xff0c;选择了基于HAL库进行开发&#xff0c;原因是HAL比较容易上手&#xff0c;像点灯、输出PWM、按键输入这种操作都很快捷。但是到ADCDMA这部分的时候发现&#xff0c;HAL库有一些地方我认为不是很合理和方便。比如DMA中断这部分&#xff0c;ST官方给出…

音视频开发系列--H264编解码总结

一、概述 H264&#xff0c;通常也被称之为H264/AVC&#xff08;或者H.264/MPEG-4 AVC或MPEG-4/H.264 AVC&#xff09; 对摄像头采集的每一帧视频需要进行编码&#xff0c;由于视频中存在空间和时间的冗余&#xff0c;需要用算法来去除这些冗余。H264是专门去除这些冗余的算法…

王者荣耀崩溃解决记录

王者荣耀竟然崩溃了 上周玩王者荣耀&#xff0c;突然就进不去了&#xff0c;点击开始游戏后应用直接就崩溃退出了。 第一反应&#xff0c;肯定是反馈给游戏客服。但是果然腾讯的游戏是找不到真客服的&#xff0c;全部都是机器人处理的&#xff0c;给了我一个毫无用处的官方回…

springboot中配置文件优先级以及分类,这你都可以不会吗?不会赶紧进来学( ̄(∞) ̄)

各位小伙伴大家好呀┗( ▔, ▔ )┛&#xff0c;马上过年了&#xff0c;但是感觉没啥期待的哈哈哈哈哈&#xff0c;现在的年说实话真的挺没劲的呜呜。 言归正传&#xff0c;我们大家在使用springboot时难免会写各种各样的配置信息&#xff0c;比如port&#xff0c;jdbc啊这些&am…

2022这一年:阳了、变轨和逆风

又到年末了&#xff0c;2022这一年应该会让人记忆深刻&#xff0c;于我而言这一年的感受有明显的分界线&#xff0c;在此之前的世界温暖一些&#xff0c;提供着能量&#xff0c;让人心生探索它的纷繁多彩&#xff1b;今年世界变得寒冷了&#xff0c;展示着它的严酷与无情。阳了…

再学C语言20:循环控制语句——for循环

在while循环中&#xff0c;建立一个重复执行固定次数的循环涉及到3个动作&#xff1a; 1&#xff09;初始化一个计数器 2&#xff09;计数器与某个有限的值比较 3&#xff09;每次执行循环&#xff0c;要在循环体中让计数器的值递增 其中&#xff0c;计数器的初始化在循环之…

【pandas】教程:6-如何计算摘要统计

Pandas 计算摘要统计 本节使用的数据为 data/titanic.csv&#xff0c;链接为 pandas案例和教程所使用的数据-机器学习文档类资源-CSDN文库 加载数据 import pandas as pdtitanic pd.read_csv("data/titanic.csv") titanic.head()PassengerId Survived Pclass \…

#Z0424. 树上的旅行

题目 Description 给出一棵有N个结点的树&#xff0c;给出Q个询问&#xff0c;求结点xj过结点K到节点yj的最短距离 Format Input 第一行一个数n 接下来共有n-1行&#xff0c;三个数u,v,len表示u和v之间存在一条边长为len 再给你Q&#xff0c;K。代表有Q个询问&#xff0…

视频 | bedtools使用介绍1

点击阅读原文跳转完整教案。基因组中的趣事&#xff08;二&#xff09;- 最长的基因2.7 million&#xff0c;最短的基因只有8 nt却能编码基因组中的趣事&#xff08;一&#xff09;&#xff1a;这个基因编码98种转录本1 Linux初探&#xff0c;打开新世界的大门1.1 Linux系统简介…

10000+条数据的内容滚动功能如何实现?

遇到脑子有问题的产品经理该怎么办&#xff1f;如果有这么一个需求要你在一个可视区范围内不间断循环滚动几千上万条数据你会怎么去实现&#xff1f; 且不说提这个需求的人是不是脑子有问题&#xff0c;这个需求能不能实现&#xff1f;肯定是可以的&#xff0c;把数据请求回来渲…

2022蓝桥杯省赛C++A组初尝试

前言 耗时三个半小时&#xff0c;看看自己不懂的有多少&#xff0c;以便明确后续备赛2023方向 耗时3个半小时&#xff0c;只拿了18分&#xff0c;没学过&#xff0c;时间再多也做不出来&#xff0c;有奥数那感觉了 据说蓝桥杯省3得做对 2填空 2大题&#xff08;30分&#x…

PMP®项目管理|不同场景使用不同沟通方式

不同沟通方式的确有适用场景和不适用场景。无效沟通的重要原因之一就是错误选择沟通方式。 我们会在工作中用到很多沟通方式&#xff0c;每种沟通方式都有适用的场合&#xff0c;也有不适用的场合&#xff0c;错误选择将使沟通变得低效甚至无效。 沟通方式主要有三种&#xf…

一百种语言的LOVE

2023年快要到来啦&#xff0c;很高兴这次我们又能一起度过~ 目录 一、前言 二、详细介绍 三、效果展示 四、代码编写 index.html script.js style.css 五、获取代码 需要源码&#xff0c;可以私信我(⊙o⊙)&#xff1f;关注我&#xff1f; 一、前言 时光荏苒&#xf…

vue element-ui 手机号校验 验证码校验 获取验证码倒数60秒无样式实现

这段时间被迫搞前端搞裂开了&#xff0c;记录一下手机号验证码校验登录的极简无样式前端实现 巨丑&#xff01;希望大佬们不介意 下面是先演示效果 点击登陆后显示校验信息 输入手机号点击获取验证码 输入符合校验的内容后点击登录提示成功 无后端交互&#xff01;&#…

从档案信息管理到档案知识管理

今年6月份的时候&#xff0c;笔者发过一篇文章《DIKW模型在档案信息资源开发中的应用》&#xff0c;简要阐述了知识管理领域非常著名的DIKW模型&#xff0c;即从数据&#xff08;Data&#xff09;→信息&#xff08;Information&#xff09;→知识&#xff08;Knowledge&#x…