JUC并发编程【java提高】4

简介: JUC并发编程【java提高】4

现在我们不用getInstance()去获取对象,而是直接通过反射创建两个对象

   //反射!
    public static void main(String[] args) throws Exception {
//        LazyMan instance = LazyMan.getInstance();
        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        LazyMan instance2 = declaredConstructor.newInstance();
        LazyMan instance = declaredConstructor.newInstance();
        System.out.println(instance.hashCode());
        System.out.println(instance2.hashCode());
    }

可以发现,单例又被破坏了,

因为构造函数里面判断的是


但是注意,我们用反射new 的对象跟类里面的lazyman对象肯定是不一样的啊,没有调用getInstance(),类里面的lazyman就一直为空,所以单例又被破坏了


解决方法,用个标志位

 private static boolean flag=false;
    private  LazyMan(){
        synchronized (LazyMan.class){
            if (flag==false){
                flag=true;
            }else {
                throw new RuntimeException("不用试图使用反射破坏异常");
            }
//            if (lazyMan!=null){
//                throw new RuntimeException("不用试图使用反射破坏异常");
//            }
        }
        System.out.println(Thread.currentThread().getName()+"ok");
    }


但是,再牛逼的加密也会解密

来我们继续破坏单例,我们把这个flag字段给它破坏了

//反射!
    public static void main(String[] args) throws Exception {
//        LazyMan instance = LazyMan.getInstance();
        Field flag = LazyMan.class.getDeclaredField("flag");
        flag.setAccessible(true);
        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        LazyMan instance = declaredConstructor.newInstance();
        flag.set(instance,false);
        LazyMan instance2 = declaredConstructor.newInstance();
        System.out.println(instance.hashCode());
        System.out.println(instance2.hashCode());
    }

结果:可以发现单例又被破坏了


完整代码:

package com.kuang.single;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
//懒汉式单例
public class LazyMan {
    private static boolean flag=false;
    private  LazyMan(){
        synchronized (LazyMan.class){
            if (flag==false){
                flag=true;
            }else {
                throw new RuntimeException("不用试图使用反射破坏异常");
            }
//            if (lazyMan!=null){
//                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、把这个对象指向这个空间
                     *
                     * 123
                     * 132 A
                     * B
                     */
                }
            }
        }
        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 flag = LazyMan.class.getDeclaredField("flag");
        flag.setAccessible(true);
        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        LazyMan instance = declaredConstructor.newInstance();
        flag.set(instance,false);
        LazyMan instance2 = declaredConstructor.newInstance();
        System.out.println(instance.hashCode());
        System.out.println(instance2.hashCode());
    }
}

那怎么解决呢?我们点进去反射的newInstance()看看呢

我们可以看到,如果类是一个枚举类型的话,就会告诉你不能使用反射破坏枚举,枚举是jdk 1.5 开始出现的,自带单例模式

4)枚举

枚举本身也是一个类

package com.kuang.single;
//enum 是一个什么? 本身也是一个Class类
public enum EnumSingle {
    INSTANCE;
    public static EnumSingle getInstance()
    {
        return INSTANCE;
    }
}
class Test{
    public static void main(String[] args) {
        EnumSingle  instance1=EnumSingle.INSTANCE;
        EnumSingle  instance2=EnumSingle.INSTANCE;
        EnumSingle  instance3=EnumSingle.getInstance();
        System.out.println(instance1);
        System.out.println(instance2);
        System.out.println(instance3);
    }
}


我们来试试用反射破坏枚举单例



package com.kuang.single;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
//enum 是一个什么? 本身也是一个Class类
public enum EnumSingle {
    INSTANCE;
    public static EnumSingle getInstance()
    {
        return INSTANCE;
    }
}
class Test{
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        EnumSingle  instance1=EnumSingle.INSTANCE;
        Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        EnumSingle instance2 = declaredConstructor.newInstance();
        System.out.println(instance1);
        System.out.println(instance2);
    }
}

下面的错误提示是枚举类没有空参的构造方法

也就是下面这句话出错了idea骗了我们

      //NoSuchMethodException: com.kuang.single.EnumSingle.<init>()
        Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(null);

正常破坏单例是应该报错不能使用反射破坏枚举


通过反编译我们可以看到,这个枚举本身也是一个class,它继承了一个枚举类

然而构造器还是空参的啊,说明我们还是被骗了



现在我们用jad.exe反编译试试

下载地址

Java反编译工具Jad的使用

jad.exe复制到.class文件夹下


我们把class字节码生成java文件看看

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   EnumSingle.java
package com.kuang.single;
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/kuang/single/EnumSingle, name);
    }
    private EnumSingle(String s, int i)
    {
        super(s, i);
    }
    public static EnumSingle getInstance()
    {
        return INSTANCE;
    }
    public static final EnumSingle INSTANCE;
    private static final EnumSingle $VALUES[];
    static 
    {
        INSTANCE = new EnumSingle("INSTANCE", 0);
        $VALUES = (new EnumSingle[] {
            INSTANCE
        });
    }
}

可以看到,不是无参构造器哦,而是有参构造器,有一个String,一个Int


现在我们修改反射代码

//        Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(null);
        Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);


完整代码:

package com.kuang.single;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
//enum 是一个什么? 本身也是一个Class类
public enum EnumSingle {
    INSTANCE;
    public static EnumSingle getInstance()
    {
        return INSTANCE;
    }
}
class Test{
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        EnumSingle  instance1=EnumSingle.INSTANCE;
        //NoSuchMethodException: com.kuang.single.EnumSingle.<init>()
//        Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(null);
        Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
        declaredConstructor.setAccessible(true);
        EnumSingle instance2 = declaredConstructor.newInstance();
        System.out.println(instance1);
        System.out.println(instance2);
    }
}

19、深入理解CAS

1)什么是CAS

大厂必须深入研究底层!!!!修内功!操作系统、计算机网络原理、组成原理、数据结构

package com.kuang.cas;
import java.util.concurrent.atomic.AtomicInteger;
public class CASDemo {
    //CAS
    public static void main(String[] args) {
        AtomicInteger atomicInteger=new AtomicInteger(2020);
        // 期望值、更新值
        // public final boolean compareAndSet(int expect, int update)
        // 如果实际值 和 期望值相同,那么就更新
        // 如果实际值 和 期望值不同,那么就不更新
        System.out.println(atomicInteger.compareAndSet(2020, 2021));//true
        System.out.println(atomicInteger.get());//2021
        //因为期望值是2020  实际值却变成了2021  所以会修改失败
        //CAS 是CPU的并发原语
        atomicInteger.getAndIncrement(); //++操作
        System.out.println(atomicInteger.compareAndSet(2020, 2021));//false
        System.out.println(atomicInteger.get());//2021
    }
}

Java无法操作内存,但是C++可以操作内存,Java可以通过native方法调用c++从而操作内存

Unsafe 类



总结:

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


好处:是不用切换线程状态,因为切换线程状态性能消耗比较大

缺点:

1:由于底层是自旋锁,循环会浪费时间

2:因为是底层的cpu操作,一次只能保证一个共享变量的原子性

3:ABA问题


CAS: ABA问题(狸猫换太子)



线程1:期望值是1,要变成2;

线程2:两个操作:

1、期望值是1,变成3

2、期望是3,变成1

所以对于线程1来说,A的值还是1,所以就出现了问题,骗过了线程1;

测试ABA问题:

package com.kuang.cas;
import java.util.concurrent.atomic.AtomicInteger;
public class CASDemo {
    //CAS
    public static void main(String[] args) {
        AtomicInteger atomicInteger=new AtomicInteger(2020);
        // 期望值、更新值
        // public final boolean compareAndSet(int expect, int update)
        // 如果实际值 和 期望值相同,那么就更新
        // 如果实际值 和 期望值不同,那么就不更新
        //============捣乱的线程===========
        System.out.println(atomicInteger.compareAndSet(2020, 2021));//true
        System.out.println(atomicInteger.get());//2021
        System.out.println(atomicInteger.compareAndSet(2021, 2020));//true
        System.out.println(atomicInteger.get());//2021
//        //因为期望值是2020  实际值却变成了2021  所以会修改失败
//        //CAS 是CPU的并发原语
//        atomicInteger.getAndIncrement(); //++操作
        //============期望的线程===========
        System.out.println(atomicInteger.compareAndSet(2020, 6666));//false
        System.out.println(atomicInteger.get());//2021
    }
}

结果:


如何解决ABA问题

原子引用

20、原子引用

解决ABA问题,引入原子引用;对应思想:乐观锁

带版本号的原子引用!

因为integer对象的问题,导致下面结果没达到预期。


compareAndSet()//返回false
 //Integer(2020)不会==Integer(2020)
当前值不会==期望值 
expectedReference == current.reference //false
//源码:
  public boolean compareAndSet(V   expectedReference,
                                 V   newReference,
                                 int expectedStamp,
                                 int newStamp) {
        Pair<V> current = pair;
        return
            expectedReference == current.reference &&
            expectedStamp == current.stamp &&
            ((newReference == current.reference &&
              newStamp == current.stamp) ||
             casPair(current, Pair.of(newReference, newStamp)));
    }
 public static void main(String[] args) {
        AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(2020,1);
        new Thread(()->{
            int stamp = atomicStampedReference.getStamp();//获得版本号
            System.out.println("a1=>"+stamp);
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(atomicStampedReference.compareAndSet(2020, 2022, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1));
            System.out.println("a2=>"+atomicStampedReference.getStamp());
            System.out.println(atomicStampedReference.compareAndSet(2022, 2020, 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(2020, 6666, stamp, stamp + 1));
            System.out.println("b2=>"+atomicStampedReference.getStamp());
        },"b").start();
    }

把2020->1,2022->2,6666->6

package com.kuang.cas;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicStampedReference;
public class CASDemo {
    public static void main(String[] args) {
        AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(1,1);
        //乐观锁的原理相同
        new Thread(()->{
            int stamp = atomicStampedReference.getStamp();//获得版本号
            System.out.println("a1=>"+stamp);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(atomicStampedReference.compareAndSet(1, 2, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1));
            System.out.println("a2=>"+atomicStampedReference.getStamp());
            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, 6, stamp, stamp + 1));
            System.out.println("b2=>"+atomicStampedReference.getStamp());
        },"b").start();
    }
}

测试结果:



21、各种锁的理解

1、公平锁、非公平锁

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

/**
 * Creates an instance of {@code ReentrantLock}.
 * This is equivalent to using {@code ReentrantLock(false)}.
 */
public ReentrantLock() {
    sync = new NonfairSync();
}

非公平锁:非常不公平,允许插队,可以改变顺序,synchronized和lock(默认都是非公平锁)

/**
 * Creates an instance of {@code ReentrantLock} with the
 * given fairness policy.
 *
 * @param fair {@code true} if this lock should use a fair ordering policy
 */
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

2、可重入锁

所有的锁都是可重入锁,有些地方叫做递归锁

你进入你家,拿到了大门的锁,也就自动拿到了里面小门的锁

1、Synchonized 锁

package com.kuang.lock;
//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");
    }
}

2、Lock 锁

package com.kuang.lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//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();
        }
    }
}

注意细节:

  • lock锁必须配对,相当于lock和 unlock 必须数量相同;
  • 在外面加的锁,也可以在里面解锁;在里面加的锁,在外面也可以解锁;

3、自旋锁

spinlock

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;
}

自己设计自旋锁

package com.kuang.lock;
import java.util.concurrent.atomic.AtomicReference;
/**
 * 自旋锁
 */
public class SpinlockDemo {
    // 默认
    // int 0
    //Thread null
    AtomicReference<Thread> atomicReference=new AtomicReference<>();
    //加锁
    public void myLock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.currentThread().getName()+"===> mylock");
        //加自旋锁
        while (!atomicReference.compareAndSet(null,thread)){
            System.out.println(Thread.currentThread().getName()+" ==> 自旋中~");
        }
    }
    //解锁
    public void myUnlock(){
        Thread thread=Thread.currentThread();
        System.out.println(thread.currentThread().getName()+"===> myUnlock");
        //解锁操作
        atomicReference.compareAndSet(thread,null);
    }
}

测试:

package com.kuang.lock;
import java.util.concurrent.TimeUnit;
public class TestSpinLock {
    public static void main(String[] args) throws InterruptedException {
        //ReentrantLock reentrantLock = new ReentrantLock();
        //reentrantLock.lock();
        //reentrantLock.unlock();
        //使用CAS实现自旋锁
        SpinlockDemo spinlockDemo=new SpinlockDemo();
        new Thread(()->{
            spinlockDemo.myLock();
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                spinlockDemo.myUnlock();
            }
        },"t1").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
            spinlockDemo.myLock();
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                spinlockDemo.myUnlock();
            }
        },"t2").start();
    }
}

测试结果:

t1===> myLock
t2===> myLock
t2 ==> 自旋中~
t2 ==> 自旋中~
t2 ==> 自旋中~
t2 ==> 自旋中~
...
...
t2 ==> 自旋中~
t2 ==> 自旋中~
t2 ==> 自旋中~
t2 ==> 自旋中~
t1===> myUnlock
t2 ==> 自旋中~
===========t2进程必须等待t1进程Unlock后,才能Unlock,在这之前进行自旋等待======
t2===> myUnlock

4、死锁

联系操作系统
第三章 处理机调度和死锁【操作系统】

package com.kuang.lock;
import java.util.concurrent.TimeUnit;
public class DeadLock {
    public static void main(String[] args) {
        String lockX= "lockX";
        String lockY= "lockY";
        new Thread(new MyThread(lockX,lockY),"t1").start();
        new Thread(new MyThread(lockY,lockX),"t2").start();
    }
}
class MyThread implements Runnable{
    private String lockA;
    private String lockB;
    public MyThread(String lockA, String lockB) {
        this.lockA = lockA;
        this.lockB = lockB;
    }
    @Override
    public void run() {
        synchronized (lockA){
            System.out.println(Thread.currentThread().getName()+" lock"+lockA+"===>get"+lockB);
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (lockB){
                System.out.println(Thread.currentThread().getName()+" lock"+lockB+"===>get"+lockA);
            }
        }
    }
}

结果:死锁


解决问题

1、使用jps -l定位进程号,

查看哪一个进程出了问题

2、使用jstack [进程号]查看进程的信息,找到死锁问题



面试,工作中!排查问题:

1、日志信息

2、堆栈信息

最后

关于本文

Markdown 74129 字数 4200 行数

HTML 66309 字数 2973 段落

本文依照狂神视频学习,

并参考,CSDN优秀博主的博文

掺杂自己的拙见

仅作学习交流使用
安利狂神说java

视频下狂神的评论:

[置顶]白漂有罪,拒绝白嫖,从点赞转发关注做起!

文章同步在公众号:狂神说 (公众号日更,记得关注)

视频文档地址:https://gitee.com/kuangstudy/openclass 记得三连转发

相关文章
|
1月前
|
Java 编译器 开发者
深入理解Java内存模型(JMM)及其对并发编程的影响
【9月更文挑战第37天】在Java的世界里,内存模型是隐藏在代码背后的守护者,它默默地协调着多线程环境下的数据一致性和可见性问题。本文将揭开Java内存模型的神秘面纱,带领读者探索其对并发编程实践的深远影响。通过深入浅出的方式,我们将了解内存模型的基本概念、工作原理以及如何在实际开发中正确应用这些知识,确保程序的正确性和高效性。
|
2月前
|
安全 Java API
JAVA并发编程JUC包之CAS原理
在JDK 1.5之后,Java API引入了`java.util.concurrent`包(简称JUC包),提供了多种并发工具类,如原子类`AtomicXX`、线程池`Executors`、信号量`Semaphore`、阻塞队列等。这些工具类简化了并发编程的复杂度。原子类`Atomic`尤其重要,它提供了线程安全的变量更新方法,支持整型、长整型、布尔型、数组及对象属性的原子修改。结合`volatile`关键字,可以实现多线程环境下共享变量的安全修改。
|
26天前
|
存储 消息中间件 安全
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
【10月更文挑战第9天】本文介绍了如何利用JUC组件实现Java服务与硬件通过MQTT的同步通信(RRPC)。通过模拟MQTT通信流程,使用`LinkedBlockingQueue`作为消息队列,详细讲解了消息发送、接收及响应的同步处理机制,包括任务超时处理和内存泄漏的预防措施。文中还提供了具体的类设计和方法实现,帮助理解同步通信的内部工作原理。
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
|
8天前
|
存储 缓存 安全
Java内存模型(JMM):深入理解并发编程的基石####
【10月更文挑战第29天】 本文作为一篇技术性文章,旨在深入探讨Java内存模型(JMM)的核心概念、工作原理及其在并发编程中的应用。我们将从JMM的基本定义出发,逐步剖析其如何通过happens-before原则、volatile关键字、synchronized关键字等机制,解决多线程环境下的数据可见性、原子性和有序性问题。不同于常规摘要的简述方式,本摘要将直接概述文章的核心内容,为读者提供一个清晰的学习路径。 ####
25 2
|
2月前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
【Java面试题汇总】多线程、JUC、锁篇(2023版)
|
2月前
|
Java 开发者
深入探索Java中的并发编程
本文将带你领略Java并发编程的奥秘,揭示其背后的原理与实践。通过深入浅出的解释和实例,我们将探讨Java内存模型、线程间通信以及常见并发工具的使用方法。无论是初学者还是有一定经验的开发者,都能从中获得启发和实用的技巧。让我们一起开启这场并发编程的奇妙之旅吧!
30 5
|
2月前
|
算法 安全 Java
Java中的并发编程是如何实现的?
Java中的并发编程是通过多线程机制实现的。Java提供了多种工具和框架来支持并发编程。
18 1
|
2月前
|
缓存 监控 Java
Java中的并发编程:理解并应用线程池
在Java的并发编程中,线程池是提高应用程序性能的关键工具。本文将深入探讨如何有效利用线程池来管理资源、提升效率和简化代码结构。我们将从基础概念出发,逐步介绍线程池的配置、使用场景以及最佳实践,帮助开发者更好地掌握并发编程的核心技巧。
|
数据采集 Java 大数据
java高并发系列 - 第14天:JUC中的LockSupport工具类,必备技能
java高并发系列 - 第14天:JUC中的LockSupport工具类,必备技能这是java高并发系列第14篇文章。 本文主要内容: 讲解3种让线程等待和唤醒的方法,每种方法配合具体的示例介绍LockSupport主要用法对比3种方式,了解他们之间的区别LockSupport位于java.util.concurrent(简称juc)包中,算是juc中一个基础类,juc中很多地方都会使用LockSupport,非常重要,希望大家一定要掌握。
1239 0
|
3天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。