高频:java并发知识

本文详细介绍了Java中的死锁现象,手写示例,以及volatile关键字的作用和原理。还探讨了原子性、指令重排的问题,涉及CAS、AQS(抽象队列同步器)和ReentrantLock的实现原理,以及线程池和多条件锁的区别。
摘要由CSDN通过智能技术生成

死锁

1、手写一个Java死锁的例子

2、问题定位死锁

1. 定位Java进程号

jps -l

2. 查看进程下线程情况

jstack 进程号

此处会输出死锁日志,找到问题即可。

volatile

1. volatile是什么?

Java虚拟机提供的轻量级同步机制

2. 作用

保证可见性

不保证原子性

禁止指令重排

3. 为什么会有可见性问题?volatile如何保证可见?

各个线程对主内存中共享变量的操作都是各个线程各自拷贝到自己的工作内存进行操作后再写回到主内存中的。这就可能存在一个线程AA修改了共享变量X的值但还未写回主内存时,另外一个线程BBB又对主内存中同一个共享变量X进行操作,但此时A线程工作内存中共享变量x对线程B来说并不可见,这种工作内存与主内存同步延迟现象就造成了可见性问题。

由于JMM(Java内存模型)导致的。具体过程如下:

由于JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存(有些地方称为栈空间),工作内存是每个线程的私有数据区域,而Jva内存模型中规定所有变量都存储在主内存,主内存是共享内存区域,所有线程都可以访问,但线程对变量的操作(读取赋值等必须在工作内存中进行,首先要将变量从主内存拷贝的自己的工作内存空问,然后对变量进行操作,操作完成后再将变量写回主内存,不能直接操作主内存中的变量,各个线程中的工作内存中存储着主内存中的变量副本拷贝,因此不同的线程间无法访问对方的工作内存,线程间的通信(传值)必须通过主内存来完成。

4. 为什么保证不了原子性?如何解决?

synchronized

atomicXXX

5. 为什么会有指令重排?指令重排会有什么问题?

多线程环境中线程交替执行,由于编译器优化重排的存在,两个线程中使用的变量能否保证一致性是无法确定的,结果无法预测。

6、线程安全的单例模式

public class SingletonDemo {
    private SingletonDemo(){}

    private static volatile SingletonDemo instance=null;

    public static SingletonDemo getInstance(){
        if(instance==null){
            synchronized(SingletonDemo.class){
                if(instance==null){
                    instance=new SingletonDemo();
                }
            }
        }
        return instance;
    }
}

DCL(双端检锁)机制不一定线程安全,原因是有指令重排序的存在,加入volatile可以禁止指令重排。
原因在于某一个线程执行到第一次检测,读取到的instance不为null时,instance的引用对象可能没有完成初始化。
instance=new SingletonDemo():可以分为以下3步完成(伪代码)
memory=allocate()1.分配对象内存空间
instance(memory)2.初始化对象
instance=memory)3.设置instance指向刚分配的内存地址,此时instance!=null

CAS

1. 什么是CAS呢?

compareAndSet

2. 底层原理?

线程比较工作内存的值与主物理内存的值是否相等,如果相等,可以修改,否则重新读取重试。

UnSafe的compareAndSwap方法

this.compareAndSwapInt(varl,var2,var5,var5+var4)

var1 AtomicInteger对象本身。
var2 该对象值得引用地址。
var4 需要变动的数量。
var5 是用var1和var2找出的主内存中真实的值。
用该对象当前的值与var5比较:
如果相同,更新var5+var4并且返回true,
如果不同,继续取值然后再比较,直到更新完成。

3. 缺点?

循环时间长的话CPU开销大

ABA(版本锁)

只能保证一个变量的原子性(原子对象)

AQS

1. 谈谈你对AQS的理解?

抽象的队列同步器,

模板方法模式

通过内置的FIFO队列来完成资源获取线程的排队工作,并通过一个int类型变量表示持有锁的状态。

2. AQS能做什么?

ReentrantLock
CountDownLatch

Semaphore
ReentrantReadWriteLock

3. 底层源码实现原理?

同步状态

volatile int state

CLH的队列

volatile Node head

volatile Node tail

内部类

volatile Node prev

volatile Node next

volatile Thread thread

volatile int waitStatus 由于是int所以初始值是0

/∥共享
static final Node SHARED new Node();
/1独占
static final Node EXCLUSIVE null;
/挑程被取清了
static final int CANCELLED=1;
/后继线程需要唤阳
static final int SIGNAL -1;
/等待condition唤l
static final int CONDITION --2;
/共享式同步状态铁取将会无条件地传播下去
static final int PROPAGATE =-3;

0 当一个Node按初始化的时候的默认值
CANCELLED 为1,表示线程获取锁的请求已经取消了

SIGNAL为-1,表示线程已是准备好了,就等资源释放了
CONDITION 为-2,表示节点在等待队列中,节点线程等待醒
PROPAGATE 为-3,当前线程处在SHARED情况下,该字段才会使用

1. 锁的多条件绑定Condition?

await/signal

三个线程交替打印ABC共5次

public class PrintABC {
    private static Lock lock = new ReentrantLock();
    private static Condition condA = lock.newCondition();
    private static Condition condB = lock.newCondition();
    private static Condition condC = lock.newCondition();
    private static  int num =0;


    public static void print(Condition sCond,Condition tCond,int remainNum){
        for (int i = 0; i < 10; i++) {
            lock.lock();
            try{
                if(num%3!=remainNum){
                    sCond.await();
                }
                System.out.print(Thread.currentThread().getName());
                num++;
                tCond.signal();
            }catch (Exception e){

            }finally {
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        new Thread(()-> print(condA,condB,0),"A").start();

        new Thread(()-> print(condB,condC,1),"B").start();

        new Thread(()-> print(condC,condA,2),"C").start();
    }
}

2. ReentrantLock实现原理?谈谈你对AQS的理解?

2. Lock与synchronized区别?

  • 实现方式不同

synchronized.是关键字属于JVM层面,monitorenter(底层是通过monitor,对象来完成,其实wait/notify梦方法也依模于monitor对象只有在同步块或方法中才德wait/notify等
monitorexit
Lock是具体类(java.utiL.concurrent.Locks.Lock)是api尽面的颌
2使用方法
synchronized不需要用户去手动释放锁,当synchronized:代码执行完后系统会白动i让线程释放对镀的占用
ReentrantLock.则需要用户去手动释放领若没有主动件放领,就有可能导致出现死领现象。
福ock()unLock()方法配合try/finally语何块来完成,
3梦待是否可中断
synchronized.不可中断,除非抛出异常或若正带运行完成
ReentrantLock可中断,1,设置超时方法tryLock(Long timeout,TimeUnit unit)
2.LockInterruptibly()放f代码块中,调所nterrupt()方法可中断
4加模是否公平
synchronized非公平领
ReentrantLock两者都可以,联以非公平锁,构造方法可以传入boolean.值,true为公平领,false为菲公平锁
5锁绵定多个条牧ondition
synchronized没有
ReentrantLock用来实现分组晚醒裙要晚的线程们,可以精确晚醒,而不是像synchronized要么随机晚醒一个线理要么晚醒全部线程。

线程池

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值