JMM与JUC

1.JMM

问题1:请你谈谈你对Volatile的理解

Volatile 是java虚拟机提供轻量级的同步机制

1. 保证可见性

2. 不保证原子性

3. 禁止指令重排

1.1、什么是JMM

JMM Java内存模型  不存在的东西,概念!约定 !

1.2、关于JMM的一些同步的约定:

1、线程解锁前,必须把共享变量立刻刷回主存,

2、线程枷锁前,必须读取主存中的最新值到工作内存中

3、加锁和解锁的是同一把锁

线程工作内存,主内存。store和write换一个位置

2.Volatile

2.1.保证可见性

package com.kuang.tvolatile;import java.util.concurrent.TimeUnit;public class Demo01 {//不加volatile ,程序就会陷入死循环,加了保证主内存的可见性public volatile static int num=0;public static void main(String[] args) {new Thread(()->{//线程对主内存的num值的变化是不知道的while (num==0){}System.out.println(num);}).start();try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}num=1;System.out.println(num);}
}

2.2不保证原子性

package com.kuang.tvolatile;import java.util.concurrent.BlockingQueue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;//不保证原子性
public class Demo02 {//volatile不保证原子性private volatile static int num=0;//改变就会重新加载主存的值,不改变就存一次到工作内存,工作内存相当于线程私有的栈帧,先这么理解public  static void  add(){num++;}
//    public   void  add1(){
//        lock.lock();
//        try {
//            num++;
//        } catch (Exception e) {
//            e.printStackTrace();
//        } finally {
//            lock.unlock();
//        }
//    }public static void main(String[] args) {//理论上num结果应该为两万for (int i = 0; i < 20; i++) {new Thread(()->{for (int j = 0; j < 1000; j++) {add();}}).start();}
//        Demo02 demo02 = new Demo02();
//        for (int i = 0; i < 10; i++) {
//            new Thread(()->{
//                for (int j = 0; j < 1000; j++) {
//                  demo02.add1();
//                }
//            }).start();
//        }while (Thread.activeCount()>2){//main gcThread.yield();}System.out.println(Thread.currentThread().getName()+"   "+num);}}

如果不加lock和synchronized,怎么样保证原子性?

使用原子类,解决原子性问题

package com.kuang.tvolatile;import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;//不保证原子性
public class Demo02 {//volatile不保证原子性
//    private volatile static int num=0;public volatile static AtomicInteger num=new AtomicInteger();
//改变就会重新加载主存的值,不改变就存一次到工作内存,工作内存相当于线程私有的栈帧,先这么理解public  static void  add(){num.getAndIncrement();//AtomicInterger+1方法,CAS}
//    public   void  add1(){
//        lock.lock();
//        try {
//            num++;
//        } catch (Exception e) {
//            e.printStackTrace();
//        } finally {
//            lock.unlock();
//        }
//    }public static void main(String[] args) {//理论上num结果应该为两万for (int i = 0; i < 20; i++) {new Thread(()->{for (int j = 0; j < 1000; j++) {add();}}).start();}
//        Demo02 demo02 = new Demo02();
//        for (int i = 0; i < 10; i++) {
//            new Thread(()->{
//                for (int j = 0; j < 1000; j++) {
//                  demo02.add1();
//                }
//            }).start();
//        }while (Thread.activeCount()>2){//main gcThread.yield();//Thread.yield() 方法是Java中的一个静态方法,用于提示调度程序当前线程愿意放弃其当前时间片。// 换句话说,它建议线程愿意暂停执行并为同一优先级的其他线程提供机会。}System.out.println(Thread.currentThread().getName()+"   "+num);}}

这些类的底层都直接和操作系统直接挂钩 !在内存中修改值!!!Unsafe类是一个很特殊的存在!

2.3 、指令重排

什么是  指令重排: 你写的程序,计算机并不是按照你写的那样去执行的。

源代码->编译器优化的重排-->指令并行也可能会重排-->内存系统也会重排-->执行

volatile 是可以保持可见性,不能保证原子性,由于内存屏障,可以保证避免指令重排的现象产生!

问:volatile在哪里避免指令重排的现象用的最多,在单例模式!!!

3.彻底玩转单例模式

饿汉式,DCL懒汉式

饿汉式

package com.kuang.single;//饿汉式
public class Hungry {private byte[] bytes1=new byte[1024*1024];private byte[] bytes2=new byte[1024*1024];private byte[] bytes3=new byte[1024*1024];private byte[] bytes4=new byte[1024*1024];private Hungry(){}private final static Hungry HUNGRY= new Hungry();public static  Hungry getHungry(){return HUNGRY;}}

DCL懒汉式 DCL:双重检测模式

原子性
package com.kuang.single;
//懒汉式
public class LazyMan {private LazyMan(){System.out.println(Thread.currentThread().getName()+"ok");}//双重检测锁,volatile内存屏障,防止指令重排,private volatile static LazyMan lazyMan;//双重检测该模式的 懒汉式单例  DCL懒汉式public static LazyMan getInstance(){if (lazyMan==null){synchronized (LazyMan.class){if (lazyMan==null){lazyMan=new LazyMan();//不是一个原子性操作/*** 1.分配内存空间* 2.执行构造方法,初始化对象* 3.把这个对象指向这个空间** 2和3的顺序,在指令重排的时候*/}//外面那一层判断空 是因为可以减少同步的时间,不会全部同步在锁当中,而一部分代码会因为不为空而直接获取对象。}}return lazyMan;}//多线程并发public static void main(String[] args) {for (int i = 0; i < 10; i++) {new Thread(()->{LazyMan.getInstance();}).start();}}}

静态内部类

package com.kuang.single;
//静态内部类
public class Holder {private Holder(){}public static Holder getInstance(){return InnerClass.HOLDER;}public static class InnerClass{private static final Holder HOLDER=new Holder();}}

进阶

package com.kuang.single;import java.lang.reflect.Constructor;
import java.lang.reflect.Field;//懒汉式
//道高一尺魔高一丈
public class LazyMan {private static boolean qingjiang=false;private LazyMan(){synchronized (LazyMan.class){if (qingjiang==false){qingjiang=true;}else {throw  new RuntimeException("不要尝试反射破坏单例模式");}}}//双重检测锁,原子性,volatile内存屏障,防止指令重排,private volatile static LazyMan lazyMan;//双重检测该模式的 懒汉式单例  DCL懒汉式public static LazyMan getInstance(){if (lazyMan==null){synchronized (LazyMan.class){if (lazyMan==null){lazyMan=new LazyMan();//不是一个原子性操作/*** 1.分配内存空间* 2.执行构造方法,初始化对象* 3.把这个对象指向这个空间** 2和3的顺序,在指令重排的时候*/}//外面那一层判断空 是因为可以减少同步的时间,不会全部同步在锁当中,而一部分代码会因为不为空而直接获取对象。}}return lazyMan;}//多线程并发
//    public static void main(String[] args) {
//        for (int i = 0; i < 10; i++) {
//            new Thread(()->{
//                LazyMan.getInstance();
//            }).start();
//        }
//    }public static void main(String[] args) throws Exception {
//        LazyMan instance = LazyMan.getInstance();Field qingjiang = LazyMan.class.getDeclaredField("qingjiang");qingjiang.setAccessible(true);Constructor<? extends LazyMan> constructor = LazyMan.class.getDeclaredConstructor(null);constructor.setAccessible(true);LazyMan instance2 = constructor.newInstance();qingjiang.set(constructor,false);LazyMan instance = constructor.newInstance();System.out.println(instance);System.out.println(instance2);}}

 

 

 

 反射无法破坏枚举

枚举在运行时没有无参构造,但是有一个有参构造,反射拿无参,会抛没有更多的方法

反射拿有参构造,则会抛出,

throw new IllegalArgumentException("Cannot reflectively create enum objects");

 

4.深入理解CAS

Unsafe类

 

5.原子引用

ABA问题

package com.kuang.cas;import java.util.concurrent.atomic.AtomicInteger;public class CASDemo {//CAS   atomicInteger.compareAndSet()  CAS就是compareAndSet的缩写:比较并交换!public static void main(String[] args){AtomicInteger atomicInteger=new AtomicInteger(2020);//对于我们平时写的SQL:乐观锁!//expect期望 update更新//public final boolean compareAndSet(int expect, int update)//如果我期望的值达到了,那么就更新,否则,就不更新,CAS 是CPU的并发原语!//捣乱的线程System.out.println(atomicInteger.compareAndSet(2020, 2021));System.out.println(atomicInteger.get());System.out.println(atomicInteger.compareAndSet(2021, 2020));System.out.println(atomicInteger.get());//        atomicInteger.getAndIncrement();//期望的线程System.out.println(atomicInteger.compareAndSet(2020, 6666));System.out.println(atomicInteger.get());}}

6.各种锁的理解

 

package com.kuang.cas;import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;public class CASDemo {//解决ABA问题,引入原子引用//CAS   atomicInteger.compareAndSet()  CAS就是compareAndSet的缩写:比较并交换!public static void main(String[] args){
//        AtomicInteger atomicInteger=new AtomicInteger(2020);AtomicStampedReference<Integer> atomic = new AtomicStampedReference<>(1, 1);new Thread(()->{int stamp = atomic.getStamp();//获取当前版本号System.out.println("a1=>"+stamp);try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("a2=>"+atomic.compareAndSet(1, 2, atomic.getStamp(), atomic.getStamp() + 1));System.out.println("a3=>"+atomic.compareAndSet(2, 1, atomic.getStamp(), atomic.getStamp() + 1));System.out.println("a4=>"+atomic.getStamp());},"a").start();//乐观锁原理是一样的new Thread(()->{int stamp = atomic.getStamp();//获取当前版本号System.out.println("b1=>"+stamp);try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("b1=>"+(atomic.compareAndSet(1, 6, stamp, stamp + 1)));System.out.println("b2=>"+atomic.getStamp());},"b").start();//
//        //对于我们平时写的SQL:乐观锁!
//
//
//        //expect期望 update更新
//        //public final boolean compareAndSet(int expect, int update)
//        //如果我期望的值达到了,那么就更新,否则,就不更新,CAS 是CPU的并发原语!
//        //捣乱的线程
//        System.out.println(atomicInteger.compareAndSet(2020, 2021));
//        System.out.println(atomicInteger.get());
//
//        System.out.println(atomicInteger.compareAndSet(2021, 2020));
//        System.out.println(atomicInteger.get());
//atomicInteger.getAndIncrement();
//
//        //期望的线程
//        System.out.println(atomicInteger.compareAndSet(2020, 6666));
//        System.out.println(atomicInteger.get());}}

对应的思想就是:乐观锁

6.1、公平锁与非公平锁

6.2、可重入锁

package com.kuang.reelock;//Synchronized
public class Demo01 {public static void main(String[] args) {Phone phone = new Phone();new Thread(()->{phone.sms();},"A").start();new Thread(()->{phone.sms();},"B").start();}
}class Phone{public synchronized void sms(){System.out.println(Thread.currentThread().getName()+"sms");call();//这里也有锁}public synchronized void call(){System.out.println(Thread.currentThread().getName()+"call");}}

 

package com.kuang.reelock.reelock;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;//Synchronized
public class Demo02{public static void main(String[] args) {Phone1 phone = new Phone1();new Thread(()->{phone.sms();},"A").start();new Thread(()->{phone.sms();},"B").start();}
}class Phone1{Lock lock =new ReentrantLock();public  void sms(){lock.lock();lock.lock();try {System.out.println(Thread.currentThread().getName()+"sms");call();//这里也有锁} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();lock.unlock();}}public  void call(){lock.lock();try {System.out.println(Thread.currentThread().getName()+"call");} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}}

 

6.3、自旋锁

自定义锁

package com.kuang.spinlock;import java.util.concurrent.atomic.AtomicReference;//自旋锁
public class SpinLockDemo {/*** int 0* Thread null*/AtomicReference<Thread> atomicReference=new AtomicReference<>();//加锁public void lock(){Thread thread = Thread.currentThread();System.out.println("加锁的是"+thread.getName());//第一次进来 为null 成功改变,while条件不成立,不自旋,但是条件没有释放,第二次进来,他不是null了。返回false但是取反为true//自旋等待解锁while (!atomicReference.compareAndSet(null,thread)){}}//解锁public void unlock(){Thread thread = Thread.currentThread();System.out.println("解锁的是"+thread.getName());atomicReference.compareAndSet(thread,null);}//}

自定义锁测试

package com.kuang.spinlock;import java.util.concurrent.TimeUnit;public class TestDemo {public static void main(String[] args) {SpinLockDemo spinLockDemo = new SpinLockDemo();new Thread(()->{spinLockDemo.lock();try {System.out.println(Thread.currentThread().getName()+"执行");TimeUnit.SECONDS.sleep(3);} catch (Exception e) {e.printStackTrace();} finally {spinLockDemo.unlock();}},"A").start();new Thread(()->{spinLockDemo.lock();try {System.out.println(Thread.currentThread().getName()+"执行");TimeUnit.SECONDS.sleep(1);} catch (Exception e) {e.printStackTrace();} finally {spinLockDemo.unlock();}},"B").start();}
}

 

6.4、死锁

死锁是多线程或多进程并发执行时可能遇到的一种问题,它具有以下四个必要条件,也被称为死锁的四个特性:

1. 互斥条件(Mutual Exclusion):至少有一个资源被多个线程或进程竞争使用,且一次只能被一个线程或进程占用。当一个线程或进程占用了资源,其他线程或进程必须等待该资源释放。

2. 请求与保持条件(Hold and Wait):线程或进程在持有至少一个资源的同时,又请求其他线程或进程持有的资源。即线程或进程在等待其他资源时,仍然保持已经占有的资源。

3. 不可剥夺条件(No Preemption):已经被一个线程或进程占用的资源不能被其他线程或进程强制性地抢占,只能由占有者主动释放。

4. 循环等待条件(Circular Wait):存在一个线程或进程的资源请求序列,使得每个线程或进程都在等待下一个线程或进程所持有的资源。形成一个闭环,导致循环等待。

当以上四个条件同时满足时,就可能发生死锁。在死锁发生时,线程或进程无法继续执行,导致系统无法正常运行。因此,死锁的四个特性是死锁问题的根本原因,需要通过合理的资源分配和调度策略来避免死锁的发生。

package com.kuang.sisuo;import java.util.concurrent.TimeUnit;public class DeadLockDemo {public static void main(String[] args) {String A="A";String B="B";new Thread(new MyThread(A,B)).start();new Thread(new MyThread(B,A)).start();}}class MyThread implements Runnable {private String A;private String B;public MyThread(String a, String b) {A = a;B = b;}@Overridepublic void run() {synchronized (A){System.out.println(A+"获取"+B);try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}synchronized (B){System.out.println(B+"获取"+A);}}}
}

如何解决问题 

栈:jstack

堆:  jprofile

调优 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ICMP差错包

ICMP报文分类 Type Code 描述 查询/差错 0-Echo响应 0 Echo响应报文 查询 3-目的不可达 0 目标网络不可达报文 差错 1 目标主机不可达报文 差错 2 目标协议不可达报文 差错 3 目标端口不可达报文 差错 4 要求分段并设置DF flag标志报文 差错 5 源路由…

Spring学习笔记10 JdbcTemplate

Spring学习笔记9 SpringIOC注解式开发_biubiubiu0706的博客-CSDN博客 JdbcTemplate是Spring提供的一个JDBC模板类,是对JDBC的封装,简化JDBC代码. 新建模块spring-jdbctemplate 引入依赖 <dependencies><!--Spring Context依赖--><dependency><groupId>…

Socket网络编程练习题三:客户端上传文件到服务器

题目 客户端&#xff1a;将本地文件上传到服务器&#xff0c;接收服务器的反馈服务端&#xff1a;接收客户端上传的文件&#xff0c;上传完毕之后给出反馈 代码实战 1、客户端代码 package com.heima;import java.io.*; import java.net.Socket;public class Client {publi…

基于Java+SpringBoot+Vue火车订票管理系统的设计与实现 前后端分离【Java毕业设计·文档报告·代码讲解·安装调试】

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

C++ -- 特殊类设计

目录 设计一个类&#xff0c;不能被拷贝 C98的做法 C11的做法 设计一个类&#xff0c;只能在堆上创建对象 实现方式1 实现方式2 设计一个类&#xff0c;只能在栈上创建对象 实现方式1 方式1的优化 实现方式2 设计一个类&#xff0c;不能被继承 设计模式 什么是设计…

Event Loop——事件循环

JS 是单线程的&#xff0c;也就是同一个时刻只能做一件事情。 那么思考&#xff1a;为什么浏览器可以同时执行异步任务呢&#xff1f;因为浏览器是多线程的。 当 JS 需要执行异步任务时&#xff0c;浏览器会另外启动一个线程去执行该任务。 也就是说&#xff0c;“JS 是单线程…

WordPress主题网站首页添加好看的四格小工具教程

直接到网站根目录创建一个css文件(文件名:sige.css),文件名可自定义(注意文件名一致) <link rel"stylesheet" href"你的网站/sige.css" type"text/css" > 然后在header.php模板最上方添加引入代码 也可自定义HTML里添加css代码最上方写…

百度交易中台之内容分润结算系统架构浅析

作者 | 交易中台团队 导读 随着公司内容生态的蓬勃发展&#xff0c;内容产出方和流量提供方最关注的“收益结算”的工作&#xff0c;也就成为重中之重。本文基于内容分润结算业务为入口&#xff0c;介绍了实现过程中的重难点&#xff0c;比如千万级和百万级数据量下的技术选型和…

[H5动画制作系列 ]变量,帧频,监听器等的生命周期基础测试

模式:按照上述抓图,actions层&#xff0c;1帧,写初始化代码,10帧写返回代码到2帧代码,2-10帧之间一直循环。1帧及10帧代码如下&#xff1a; 如果程序在1-10之间循环,会反复创建变量i,多个监听器等。所以,第一帧最好执行一次即可&#xff0c;程序在2-10帧之间一直循环。

OpenAI 更新 ChatGPT:支持图片和语音输入【附点评】

一、消息正文 9月25日消息,近日OpenAI宣布其对话AI系统ChatGPT进行升级,添加了语音输入和图像处理两个新功能。据OpenAI透露,这些新功能将在未来两周内面向ChatGPT Plus付费用户推出,免费用户也将很快可以使用这些新功能。这标志着ChatGPT继续朝着多模态交互的方向发展,为用户提…

计算机组成原理之初识计算机硬件,帮你拆开电脑看看里面的组成!!!

大家好&#xff0c;欢迎阅读《计算机组成原理》的系列文章&#xff0c;本系列文章主要教内容是从零学习计算机组成原理&#xff0c;内容通俗易懂&#xff0c;大家好好学习吧&#xff01;&#xff01;&#xff01; 更多的优质内容&#xff0c;请点击以下链接查看哦~~ ↓ ↓ ↓ …

大数据Flink(八十九):Temporal Join(快照 Join)

文章目录 Temporal Join(快照 Join) Temporal Join(快照 Join) Temporal Join 定义(支持 Batch\Streaming):Temporal Join 在离线的概念中其实是没有类似的 Join 概念的,但是离线中常常会维护一种表叫做 拉链快照表,使用一个明细表去 join 这个 拉链快照表 的 join …

文件的编译与链接

目录 翻译环境与链接环境&#xff1a; 翻译环境&#xff1a; 编译器部分&#xff1a; 预处理&#xff1a; 编译&#xff1a; 词法分析&#xff1a; 语法分析&#xff1a; 语义分析&#xff1a; 汇编&#xff1a; 小总结&#xff1a; 链接器部分&#xff1a; 运行环境…

Tomcat报404问题的原因分析

1.未配置环境变量 按照需求重新配置即可。 2.IIs访问权限问题 注意:这个问题有的博主也写了,但是这个问题可有可无,意思是正常情况下,有没有都是可以访问滴放心 3.端口占用问题 端口占用可能会出现这个问题,因为tomcat的默认端口号是8080,如果在是运行tomcat时计算机的…

ElementUI -- Mock.js介绍和使用与首页导航栏左侧菜单搭建

1.1 mockjs介绍 Mock.js是一个用于生成随机数据和模拟接口请求的JavaScript库。它可以帮助开发人员在前端开发过程中模拟后端接口的返回数据&#xff0c;以便进行前端页面的开发和测试。 Mock.js有两个重要的特性风靡前端: 数据类型丰富 Mock.js提供了一套简单易用的API&#x…

postman接口测试—Restful接口开发与测试

开发完接口&#xff0c;接下来我们需要对我们开发的接口进行测试。接口测试的方法比较多&#xff0c;使用接口工具或者Python来测试都可以&#xff0c;工具方面比如之前我们学习过的Postman或者Jmeter &#xff0c;Python脚本测试可以使用Requests unittest来测试。 测试思路…

蓝桥杯每日一题2023.9.29

蓝桥杯大赛历届真题 - C&C 大学 B 组 - 蓝桥云课 (lanqiao.cn) 题目描述1 题目分析 看见有32位&#xff0c;我们以此为入手点&#xff0c; B代表字节1B 8b b代表位&#xff0c;32位即4个字节 (B) 1KB 1024B 1MB 1024KB (256 * 1024 * 1024) / 4 67108864 故答案…

面向对象【递归方法】

文章目录 递归编写递归函数递归的工作原理常见的递归应用场景递归注意点 递归 递归是一种解决问题的方法&#xff0c;其中一个函数调用自身以解决较小的实例&#xff0c;直到达到基本情况&#xff08;停止条件&#xff09;&#xff0c;然后开始返回结果。递归可以让我们更容易地…

Linux 回收内存到底怎么计算anon/file回收比例,只是swappiness这么简单?

概述 Linux内核为了区分冷热内存,将page以链表的形式保存,主要分为5个链表,除去evictable,我们主要关注另外四个链表:active file/inactive file,active anon和inactive anon链表,可以看到这主要分为两类,file和anon page,内存紧张的时候,内核开始从inactive tail定…

AI写稿软件,最新的AI写稿软件有哪些

写作已经成为各行各业无法绕开的重要环节。不论是企业的广告宣传、新闻媒体的报道、还是个人自媒体的内容创作&#xff0c;文字都扮演着不可或缺的角色。随着信息的爆炸式增长&#xff0c;写作的需求也不断攀升&#xff0c;这使得许多人感到困扰。时间不够用、创意枯竭、写作技…