2024年阿里+腾讯+快手offer都已拿到,JUC-03

System.out.println(“t=>” + t); //正常的返回结果

System.out.println(“u=>” + u); //抛出异常的 错误信息

}).exceptionally((e) -> {

//error回调

System.out.println(e.getMessage());

return 404;

}).get());

whenComplete: 有两个参数,一个是t 一个是u

T:是代表的 正常返回的结果;

U:是代表的 抛出异常的错误信息;

如果发生了异常,get可以获取到exceptionally返回的值;

volatile

1)保证可见性

public class JMMDemo01 {

// 如果不加volatile 程序会死循环

// 加了volatile是可以保证可见性的

private volatile static Integer number = 0;

public static void main(String[] args) {

//main线程

//子线程1

new Thread(()->{

while (number==0){

}

}).start();

try {

TimeUnit.SECONDS.sleep(2);

} catch (InterruptedException e) {

e.printStackTrace();

}

//子线程2

new Thread(()->{

while (number==0){

}

}).start();

try {

TimeUnit.SECONDS.sleep(2);

} catch (InterruptedException e) {

e.printStackTrace();

}

number=1;

System.out.println(number);

}

}

2)不保证原子性

线程A在执行任务的时候,不能被打扰的,也不能被分割的,要么同时成功,要么同时失败。

/**

  • 不保证原子性

  • number <=2w

*/

public class VDemo02 {

private static volatile int number = 0;

public static void add(){

number++;

//++ 不是一个原子性操作,是两个~3个操作

//

}

public static void main(String[] args) {

//理论上number === 20000

for (int i = 1; i <= 20; i++) {

new Thread(()->{

for (int j = 1; j <= 1000 ; j++) {

add();

}

}).start();

}

while (Thread.activeCount()>2){

//main gc

Thread.yield();

}

System.out.println(Thread.currentThread().getName()+“,num=”+number);

}

}

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

在这里插入图片描述

使用原子类

在这里插入图片描述

public class VDemo02 {

private static volatile AtomicInteger number = new AtomicInteger();

public static void add(){

// number++;

number.incrementAndGet(); //底层是CAS保证的原子性

}

public static void main(String[] args) {

//理论上number === 20000

for (int i = 1; i <= 20; i++) {

new Thread(()->{

for (int j = 1; j <= 1000 ; j++) {

add();

}

}).start();

}

while (Thread.activeCount()>2){

//main gc

Thread.yield();

}

System.out.println(Thread.currentThread().getName()+“,num=”+number);

}

}

3)禁止指令重排

什么是指令重排?

写的程序,计算机并不是按照我们自己写的那样去执行的

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

volatile可以避免指令重排:

volatile中会加一道内存的屏障,这个内存屏障可以保证在这个屏障中的指令顺序。

在这里插入图片描述

4)总结
  • volatile可以保证可见性;

  • 不能保证原子性

  • 由于内存屏障,可以保证避免指令重排的现象产生

单例模式

1)饿汉式

/**

  • 饿汉式单例

*/

public class Hungry {

/**

  • 可能会浪费空间

*/

private byte[] data1=new byte[1024*1024];

private byte[] data2=new byte[1024*1024];

private byte[] data3=new byte[1024*1024];

private byte[] data4=new byte[1024*1024];

private Hungry(){

}

private final static Hungry hungry = new Hungry();

public static Hungry getInstance(){

return hungry;

}

}

2)DCL懒汉式

//懒汉式单例模式

public class LazyMan {

private static boolean key = false;

private LazyMan(){

synchronized (LazyMan.class){

if (key==false){

key=true;

}

else{

throw new RuntimeException(“不要试图使用反射破坏异常”);

}

}

System.out.println(Thread.currentThread().getName()+" ok");

}

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、把这个对象指向这个空间

  • 就有可能出现指令重排问题

  • 比如执行的顺序是1 3 2 等

  • 我们就可以添加volatile保证指令重排问题

*/

}

}

}

return lazyMan;

}

//单线程下 是ok的

//但是如果是并发的

public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {

//Java中有反射

// LazyMan instance = LazyMan.getInstance();

Field key = LazyMan.class.getDeclaredField(“key”);

key.setAccessible(true);

Constructor declaredConstructor = LazyMan.class.getDeclaredConstructor(null);

declaredConstructor.setAccessible(true); //无视了私有的构造器

LazyMan lazyMan1 = declaredConstructor.newInstance();

key.set(lazyMan1,false);

LazyMan instance = declaredConstructor.newInstance();

System.out.println(instance);

System.out.println(lazyMan1);

System.out.println(instance == lazyMan1);

}

}

3)静态内部类

//静态内部类

public class Holder {

private Holder(){

}

public static Holder getInstance(){

return InnerClass.holder;

}

public static class InnerClass{

private static final Holder holder = new Holder();

}

}

单例不安全, 因为反射

4)枚举

//enum 是什么? enum本身就是一个Class 类

public enum EnumSingle {

INSTANCE;

public EnumSingle getInstance(){

return INSTANCE;

}

}

class Test{

public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

EnumSingle instance1 = EnumSingle.INSTANCE;

Constructor declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);

declaredConstructor.setAccessible(true);

//java.lang.NoSuchMethodException: com.ogj.single.EnumSingle.()

EnumSingle instance2 = declaredConstructor.newInstance();

System.out.println(instance1);

System.out.println(instance2);

}

}

枚举类型的最终反编译源码:

public final class EnumSingle extends Enum

{

public static EnumSingle[] values()

{

return (EnumSingle[])$VALUES.clone();

}

public static EnumSingle valueOf(String name)

{

return (EnumSingle)Enum.valueOf(com/ogj/single/EnumSingle, name);

}

private EnumSingle(String s, int i)

{

super(s, i);

}

public EnumSingle getInstance()

{

return INSTANCE;

}

public static final EnumSingle INSTANCE;

private static final EnumSingle $VALUES[];

static

{

INSTANCE = new EnumSingle(“INSTANCE”, 0);

$VALUES = (new EnumSingle[] {

INSTANCE

});

}

}

深入理解CAS

public class casDemo {

//CAS : compareAndSet 比较并交换

public static void main(String[] args) {

AtomicInteger atomicInteger = new AtomicInteger(2020);

//boolean compareAndSet(int expect, int update)

//期望值、更新值

//如果实际值 和 我的期望值相同,那么就更新

//如果实际值 和 我的期望值不同,那么就不更新

System.out.println(atomicInteger.compareAndSet(2020, 2021));

System.out.println(atomicInteger.get());

//因为期望值是2020 实际值却变成了2021 所以会修改失败

//CAS 是CPU的并发原语

atomicInteger.getAndIncrement(); //++操作

System.out.println(atomicInteger.compareAndSet(2020, 2021));

System.out.println(atomicInteger.get());

}

}

Unsafe 类

在这里插入图片描述

在这里插入图片描述

CAS:比较当前工作内存中的值 和 主内存中的值,如果这个值是期望的,那么则执行操作!如果不是就一直循环,使用的是自旋锁。

原子引用解决ABA问题

带版本号的 原子操作!

Integer 使用了对象缓存机制,默认范围是-128~127,推荐使用静态工厂方法valueOf获取对象实例,而不是new,因为valueOf使用缓存,而new一定会创建新的对象分配新的内存空间。

在这里插入图片描述

带版本号的原子操作

package com.marchsoft.lockdemo;

import java.util.concurrent.TimeUnit;

import java.util.concurrent.atomic.AtomicStampedReference;

/**

  • Description:

  • @author jiaoqianjin

  • Date: 2020/8/12 22:07

**/

public class CASDemo {

/**AtomicStampedReference 注意,如果泛型是一个包装类,注意对象的引用问题

  • 正常在业务操作,这里面比较的都是一个个对象

*/

static AtomicStampedReference atomicStampedReference = new

AtomicStampedReference<>(1, 1);

// CAS compareAndSet : 比较并交换!

public static void main(String[] args) {

new Thread(() -> {

int stamp = atomicStampedReference.getStamp(); // 获得版本号

System.out.println(“a1=>” + stamp);

try {

TimeUnit.SECONDS.sleep(1);

} catch (InterruptedException e) {

e.printStackTrace();

}

// 修改操作时,版本号更新 + 1

atomicStampedReference.compareAndSet(1, 2,

atomicStampedReference.getStamp(),

atomicStampedReference.getStamp() + 1);

System.out.println(“a2=>” + atomicStampedReference.getStamp());

// 重新把值改回去, 版本号更新 + 1

System.out.println(atomicStampedReference.compareAndSet(2, 1,

atomicStampedReference.getStamp(),

atomicStampedReference.getStamp() + 1));

System.out.println(“a3=>” + atomicStampedReference.getStamp());

}, “a”).start();

// 乐观锁的原理相同!

new Thread(() -> {

int stamp = atomicStampedReference.getStamp(); // 获得版本号

System.out.println(“b1=>” + stamp);

try {

TimeUnit.SECONDS.sleep(2);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(atomicStampedReference.compareAndSet(1, 3,

stamp, stamp + 1));

System.out.println(“b2=>” + atomicStampedReference.getStamp());

}, “b”).start();

}

}

1)公平锁,非公平锁

公平锁:非常公平,不能插队,必须先来后到

非公平锁:非常不公平,允许插队,可以改变顺序

2)可重入锁

在这里插入图片描述

Synchonized 锁

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”);

}

}

Lock 锁

//lock

public class Demo02 {

public static void main(String[] args) {

Phone2 phone = new Phone2();

new Thread(()->{

phone.sms();

},“A”).start();

new Thread(()->{

phone.sms();

},“B”).start();

}

}

class Phone2{

Lock lock=new ReentrantLock();

public void sms(){

lock.lock(); //细节:这个是两把锁,两个钥匙

//lock锁必须配对,否则就会死锁在里面

try {

System.out.println(Thread.currentThread().getName()+“=> sms”);

call();//这里也有一把锁

} catch (Exception e) {

e.printStackTrace();

}finally {

lock.unlock();

}

}

public void call(){

lock.lock();

try {

System.out.println(Thread.currentThread().getName() + “=> call”);

}catch (Exception e){

e.printStackTrace();

}

finally {

lock.unlock();

}

}

}

  1. lock锁必须配对,相当于lock和 unlock 必须数量相同;

  2. 在外面加的锁,也可以在里面解锁;在里面加的锁,在外面也可以解锁;

3)自旋锁

public final int getAndAddInt(Object var1, long var2, int var4) {

int var5;

do {

var5 = this.getIntVolatile(var1, var2);

} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

return var5;

}

自我设计自旋锁

public class SpinlockDemo {

// 默认

// int 0

//thread null

AtomicReference atomicReference=new AtomicReference<>();

//加锁

public void myLock(){

Thread thread = Thread.currentThread();

System.out.println(thread.getName()+“===> mylock”);

//自旋锁

while (!atomicReference.compareAndSet(null,thread)){

System.out.println(Thread.currentThread().getName()+" ==> 自旋中~");

}

}

//解锁

public void myUnlock(){

Thread thread=Thread.currentThread();

System.out.println(thread.getName()+“===> myUnlock”);

atomicReference.compareAndSet(thread,null);

}

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

读者福利

分享一份自己整理好的Java面试手册,还有一些面试题pdf

不要停下自己学习的脚步

字节跳动的面试分享,为了拿下这个offer鬼知道我经历了什么

字节跳动的面试分享,为了拿下这个offer鬼知道我经历了什么

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

自旋中~");

}

}

//解锁

public void myUnlock(){

Thread thread=Thread.currentThread();

System.out.println(thread.getName()+“===> myUnlock”);

atomicReference.compareAndSet(thread,null);

}

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。[外链图片转存中…(img-5uhktIGk-1713291141482)]

[外链图片转存中…(img-twxLrA3Z-1713291141482)]

[外链图片转存中…(img-AiwRXOrf-1713291141483)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

读者福利

分享一份自己整理好的Java面试手册,还有一些面试题pdf

不要停下自己学习的脚步

[外链图片转存中…(img-1hcuUQ4F-1713291141483)]

[外链图片转存中…(img-tcViEHKN-1713291141484)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值