多线程7

常见锁的策略

锁策略具体的情况

一.悲观锁VS乐观锁

判断条件:加锁的时候,预测当前锁冲突的概率是大还是小

预测当前锁冲突概率大,后续要做的工作往往就会更多.加锁开销就更大(时间,系统资源)=>悲观锁

预测当前锁冲突概率不大,后续要做的工作往往就更少.加锁开销就更小(时间,系统资源)=>乐观锁

synchronized是属于既是乐观锁,也是悲观锁,它支持自适应.

synchronized能够自动的统计出当前的锁冲突的次数,进行判定当前是锁冲突概率低,

还是概率高当冲突概率低的时候,就是按照乐观锁的方式来执行的.(速度更快)

当冲突概率高的时候,就会升级成悲观锁的方式来执行.(做的工作更多)

二.重量级锁VS轻量级锁

判断条件:做的事情多少,

做的事情多少叫重量级锁,做的事情少,叫轻量级锁。

一般来说,悲观锁,往往就是重量级锁加锁过程做的事情多,重量

一般来说,乐观锁,往往就是轻量级锁加锁过程做的事情少,轻量

synchronized是属于既是.重量级锁VS轻量级锁,它支持自适应.

三.自旋锁VS挂起等待锁

自旋锁
    void lock(){
        while (true){
            if (){
                continue;
            }
            获取到锁
                    break;
        }
    }

消耗了更多的cpu资源但是一旦锁被释放就能第一时间拿到锁拿到锁的速度更快,由于一直在执行这样的操作,所以一直消耗cpu。

挂起等待锁

挂起等待锁,是重量级锁的一种典型实现方式

当尝试加锁,并且锁被占用了,出现锁冲突,就会让当前这个尝试加锁的线程,被挂起.(阻塞状态)此时这个线程就不会参与调度了,直到这个锁被释放,然后系统才能唤醒这个线程,去尝试重新获取锁

(拿锁慢,节省cput的消耗)消耗的时间更长一旦线程被阻塞了,啥时候被唤醒这个过程是不可控的,可能会经历很长很长的时间。

synchronized轻量级锁部分,基于自旋锁实现;重量级锁部分,基于挂起等待锁实现.

四.可重入锁vs不可重入锁

synchronized就是可重入锁,一个线程,针对这把锁,连续加锁两次,不会死锁

不可重入锁,就会造成连续加锁两次之后会死锁。

五.公平锁炎VS非公平锁

公平锁:严格按照先来后到的顺序来获取锁哪个线程等待的时间长,哪个线程就拿到锁

非公平锁:若干个线程,各凭本事,随机的获取到锁和线程等待时间无关了。

公平锁:相当于买饭,先排队的人,先吃饭,后排队的人后买饭

非公平锁,像抢票,所有人在同一时间,一起抢票。

synchronized属于非公平锁多个线程,尝试获取这个锁

六.互斥锁VS读写锁

互斥锁:给读操作加锁:读的时候,不能写给写操作加锁:写的时候,不能读。

java的读写锁是这样设定的:

1)读锁和读锁之间,不会产生互斥

2)写锁和写锁之间,会产生互斥

3)读锁和写锁之间会产生互斥

日常开发中,有很多场景,景,属于“读多,写少”,用读写锁提高效率。

synchronized实现原理

synchronized即使悲观锁,也是乐观锁,既是轻量级锁,也是重量级锁.轻量级锁是自旋锁实现,重量级锁是挂起等待锁实现.是可重入锁,不是读写锁,是非公平锁.

synchronized 的"自适应"锁升级的过程:

1)未加锁的状态 (无锁)--->代码中开始调用执行synchronized->(2)

2)偏向锁--->遇到锁冲突

3)轻量级锁--->冲突进一步提升

4)重量级锁

偏向锁的作用:能不加锁,就不加锁,能晚加锁,就晚加锁。

就像买房子,刚开始没加锁的状态的时候,就是没买,然后跟房地产的人说,再看看,这时候就相当于偏向锁,等到有人想要买房子的时候,就会提升为轻量锁,直接将房子叫了定金,如果这时候还有很多人买,冲突加剧,就会变成重量级锁。

锁消除

最典型的,就只在一个线程里,使用synchronized.

由于编译器优化,需要保证优化后的逻辑和优化前是要等价的这里做的是比较保守的.能够起到的作用有限的。

 就是将很多的步骤合并,使其简化。

最终目的:提高效率

锁粗化

锁的粒度

加锁的范围内,,包含多少代码包含的代码越多,就认为锁的粒度就越粗反之,锁的粒度就越细。

  synchronized (this){
            fun1();
        }
        synchronized (this){
            fun2();
        }
        synchronized (this){
            fun3();
        }

合并 

 synchronized (this){
            fun1();
            fun2();
            fun3();
        }

synchronized的优化策略

1)锁升级[重要]=>高频考点.(把偏向锁,理解好,解释清楚)

2)锁消除

3)锁粗化

CAS

这是一条cpu指令,就可以完成比较和交换这样的一套操作下来(原子的)。

 boolean cas(内存地址,寄存器1,寄存器2)
    {
        if (内存地址==寄存器1){
            把  内存地址的值和 寄存器2 的值,进行交换
            return  true;
        }
        return  false;
    }

用来赋值

在java 代码中也就可以使用CAS操作了

只要代码有了加锁,此时代码就和“高性能”。

import java.util.concurrent.atomic.AtomicInteger;

public class Test5 {

        private  static AtomicInteger count=new AtomicInteger(0);
    public static void main(String[] args) {
        Thread t1=new Thread(()->{
           for (int i=0;i<5000;i++){
               count.getAndIncrement();//count++;
               count.incrementAndGet();//++count;
               count.getAndIncrement();//count--;
               count.decrementAndGet(); //--count;
               count.getAndAdd(10);//count+=10;
           }
        });

    }

}
--

此处我们的代码中,没有用到任何的加锁操作的,

这一套,基于CAS,不加锁来实现线程安全代码的方式,也称为“无锁编程

还可以基于CAS来封装成自旋锁(自旋锁也是基于CAS来实现的),

这样做,其实也就失去了“无锁编程”的意义了.

public class SpinLock{
    private Thread owner=null;//持有锁的线程是谁未加锁状态,此时owner就是null.
    public void lock(){
     while (!CAS(this.owner-->此处的比较和赋值是原子的~~就可以借助这样的逻辑来进行行加锁的实现,null-->如果当前前owner的值为null就把当前调用lock方法的线程引l用赋值到owner里面此时CAS返回true,再来!取反,就是false,循环结束了,Thread.currentThread()))
{
         
     }
    }
    public void unlock(){
        this.owner=null;
    }
}

如果当前owner不为null,此时CAS不会进行任何交换/赋值直接返回false,再来!取反,就是true,就要继续循环,再判定一次~~

CAS的ABA问题属于CAS的一个重要注意事项.

CAS 这里核心是"比较-发现相等-交换"=>潜台词发现相等=>数据中间没有发生过任何改变

此处CAS期望的是,中间没有其他线程修改过这个数据实际上,不一定.可能会出现,其他线程,把这个数据,从A->B->A看起来好像没变,好像没人改,其实是已经变过了,但是影响不大。

相关推荐

  1. 线7

    2024-04-13 06:28:04       21 阅读
  2. Linux线

    2024-04-13 06:28:04       52 阅读
  3. 线

    2024-04-13 06:28:04       43 阅读
  4. 【Flutter】线

    2024-04-13 06:28:04       31 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-13 06:28:04       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-13 06:28:04       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-13 06:28:04       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-13 06:28:04       20 阅读

热门阅读

  1. 如何升级node.js版本

    2024-04-13 06:28:04       19 阅读
  2. K8S资源管理之LimitRange

    2024-04-13 06:28:04       19 阅读
  3. Lua语法(二)——闭包/日期和时间

    2024-04-13 06:28:04       18 阅读
  4. Apache Storm的详细配置

    2024-04-13 06:28:04       18 阅读
  5. 优雅关闭jar程序shell 脚本

    2024-04-13 06:28:04       20 阅读
  6. Gateway基本配置与使用介绍

    2024-04-13 06:28:04       18 阅读
  7. NVIC中断分组和配置

    2024-04-13 06:28:04       17 阅读
  8. 多线程交替打印

    2024-04-13 06:28:04       32 阅读
  9. 简单了解仿真测试

    2024-04-13 06:28:04       20 阅读
  10. 【技术支持】禁止html中referer

    2024-04-13 06:28:04       19 阅读
  11. .NET 设计模式—策略模式(Strategy Pattern)

    2024-04-13 06:28:04       20 阅读
  12. Docker 安装Kali Linux作为攻防演练的工具

    2024-04-13 06:28:04       36 阅读