多线程之进阶修炼

常见的锁策略

乐观锁vs悲观锁

加锁的时候预测,锁出现的竞争的概率大还是小

大--->悲观锁 小--->乐观锁

重量级锁vs轻量级锁

加锁这个操作开销大--->重量级锁

加锁这个操作开销小--->轻量级锁

挂起等待锁vs自旋锁

挂起等待锁:遇到锁冲突,就先线程阻塞,之后再唤醒

自旋锁:遇到锁冲突,先不着急阻塞,先进行重试

可重入锁vs不可重入锁

公平锁vs不公平锁

先来后到

普通互斥锁vs读写锁

普通互斥锁:加锁,解锁

读写锁:加读锁,加写锁,解锁

synchronized是可重入锁非公平锁不是读写锁,其他皆可

synchronized底层的操作

锁升级(锁的自适应过程)

无锁 没有进入代码块

|

|

|

偏向锁 一进入synchronized代码块(然而偏向锁并没有真正加锁而是标记,如果没有线程 与其竞争,那么就一直标记到"解锁",也就解除标记)

|

|

|

自旋锁 达到一定条件进入自旋锁(轻量级)

|

|

|

重量级锁 达到一定条件进入重量级锁

锁消除

针对synchronized进行的一种编译器优化,代码逻辑不变

编译器察觉到某个线程不需要加锁但是你加锁了,会尝试把锁去掉

锁粗化

锁的粒度

加锁和解锁中间的代码逻辑复杂粒度就会大

CAS

主包来简单解释一下

CAS是解决线程安全的一种方式,全称是Compare And Swap,翻译过来就是比较并且交换,对它的具体解释也是类似的

CAS是cpu上的一条指令,原子性的

++伪代码方面++:(伪代码不能够编译运行,只是表示逻辑)

java 复制代码
boolean CAS(&address,ExpectValue,SwapValue){
        if(&address==ExpectValue){
            &address=SwapValue;
        return true;
     }
return false;
}  

CAS又是怎样实现的

++CPU++提供了CAS这样一条指令----->

++操作系统++就可以对CAS进行封装------>

操作系统提供API,通过API就可以使用CAS机制------->

++JVM++就可以进行封装调用操作系统的API-------->

++Java应用程序++代码中就可以使用JVM的API

CAS在Java的应用

实现原子类

实际应用

java不支持运算符重载,运算符重载指的是可以让各种运算符给某个类的对象来使用

java 复制代码
public class demo32 {
    //不使用int,使用原子类
    public  static AtomicInteger count = new AtomicInteger(0);

    public static void main(String[] args) throws InterruptedException {

        Thread t1= new Thread(()->{
            for (int i = 0; i <50000; i++) {
                //count++;
                count.getAndIncrement();
            }
        });
        Thread t2= new Thread(()->{
            for (int i = 0; i <50000; i++) {
                //count++;
                count.getAndIncrement();
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("count="+count.get());
    }
}

实现自旋锁

synchronized内部"自旋"就是靠CAS,基于CAS实现的是轻量级锁,使用CAS就不必加锁,此处的锁指的是重量级锁

CAS的ABA问题

CAS循环检测判定是否有其他线程进行穿插执行了,判定依据是检测的值是否改变,但这样是不够严谨的,可能另一个线程也进行修改了但将A--->B,但随后又将B--->A,这就导致判定时认为没有

解决方案:引入"版本号"这个概念,约定版本号只能加不能减

JUC的常见类

Callable接口

在描述一个任务时,需要有返回值<T> call,而对于Runnable来说void run就不需要返回值

实际应用

带有返回值的任务可以明确此处的作用,能够更好阅读代码

java 复制代码
public class demo34 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum= 0;
                for (int i=1;i<=1000;i++){
                    sum += i;
                }
                return sum;
            }
        };
        //对于Thread来说,不能以callable作为参数
        //需要搭配FutureTask
        FutureTask<Integer> futureTask =new FutureTask<>(callable);
         Thread thread = new Thread(futureTask);
         thread.start();
         //get方法拿到call的返回结果如果没有执行完就会进行阻塞等待
        System.out.println(futureTask.get());
    }
}

ReentrantLock

也是可重入锁但也和synchronized有所不同

实际应用

java 复制代码
public class demo35 {
    private static int count =0;
    public static void main(String[] args) throws InterruptedException {
        ReentrantLock Locker = new ReentrantLock();
        Thread t1= new Thread(()->{
            for (int i = 0; i < 50000; i++) {
                //无论lock和unlock之间有return或者throws就不能够释放锁搭配try和finally九都会解锁
                try {
                Locker.lock();
                count++;
                }finally {
                Locker.unlock();
                }
            }
        });
        Thread t2= new Thread(()->{
            for (int i = 0; i < 50000; i++) {
                try {
                    Locker.lock();
                    count++;
                }finally {
                    Locker.unlock();
                }
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
}

特点

1.支持trylock

java 复制代码
  if(Locker.tryLock()) {
                        count++;
                    }
                    else {
                        //放弃加锁
                    }

lock的行为,加锁失败就会阻塞等待

trylock,加锁失败,可以直接放弃,也支持指定超时时间

2.支持公平锁

3.等待通知机制

synchronized,搭配wait&notify,随机唤醒一个

ReentrantLock搭配Condition类,唤醒功能丰富&指定唤醒

信号量Semaphore

信号量其实就是一个"计数器",用来统计"可用资源"的个数

P:申请资源 V:释放资源

实际应用

java 复制代码
public class demo36 {
    public static void main(String[] args) throws InterruptedException {
        Semaphore semaphore = new Semaphore(3);
        semaphore.acquire();
        System.out.println("进行P操作");
        semaphore.acquire();
        System.out.println("进行P操作");
        semaphore.acquire();
        System.out.println("进行P操作");
        semaphore.release();
        System.out.println("进行V操作");
        semaphore.acquire();
        System.out.println("进行P操作");
    }
}

信号量中如果计数器已经是0了,继续执行P申请资源,就会触发阻塞

Semaphore可以作为锁使用

java 复制代码
public class demo37 {

    private static int count = 0;
    public static void main(String[] args) throws InterruptedException {
        Semaphore semaphore =new Semaphore(1);
        Thread t1 = new Thread(()->{
            for (int i = 0; i < 50000; i++) {
                try {
                    semaphore.acquire();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                count++;
                semaphore.release();
            }
        });
        Thread t2 = new Thread(()->{
            for (int i = 0; i < 50000; i++) {
                try {
                    semaphore.acquire();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                count++;
                semaphore.release();
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("count="+count);
    }
}

CountDownLatch

针对特定的场景,大任务拆解成小任务,必须等小的任务全部完成,才能算完成

相关推荐
014-code2 小时前
线程池参数怎么配才不翻车
java
吴梓穆2 小时前
UE5 c++ 常用方法
java·c++·ue5
hoiii1872 小时前
CSTR反应器模型的Simulink-PID仿真(MATLAB实现)
开发语言·matlab
王夏奇2 小时前
python中的__all__ 具体用法
java·前端·python
明湖起风了2 小时前
mqtt消费堆积
java·jvm·windows
Free Tester2 小时前
如何判断 LeakCanary 报告的严重程度
java·jvm·算法
炘爚2 小时前
C++ 右值引用与程序优化
开发语言·c++
si莉亚3 小时前
ROS2安装EVO工具包
linux·开发语言·c++·开源
清心歌3 小时前
CopyOnWriteArrayList 实现原理
java·开发语言