失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 一道面试题验出JAVA多线程功底 深入浅出多线程 进来看看

一道面试题验出JAVA多线程功底 深入浅出多线程 进来看看

时间:2021-08-19 18:23:34

相关推荐

一道面试题验出JAVA多线程功底 深入浅出多线程 进来看看

前言

我前几天出了一道面试题,问题是解决高并发限流的问题,一个面试者给我提到了计数器的功能,我觉得很有必要在这里说一下。

他给我说到他们公司用到的一个计数器,当请求量达到3000的化就不去处理。

高并发场景,就会遇到限流场景。先上他给我写的代码。

代码

定义一个计数器接口。

public interface Counter {

//加

int incr();

//减

int decr();

//获取当前值

int get();

}

定义接口实现类

public class CounterBasic implements Counter {

volatile int i=0;

@Override

public int incr() {

return i++;

}

@Override

public int decr() {

return i--;

}

@Override

public int get() {

return i;

}

}

我们测试以他写的这个计数器在高并发情况下能不能使用。

public class Test {

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

final Counter ct=new CounterBasic();

for(int i=0;i<2;i++){

new Thread(()->{

long begin=System.nanoTime();

for(int j=0;j<10000;j++){

ct.incr();

}

}).start();

}

Thread.sleep(6000L);

System.out.println("计数器的最终结果:"+ct.get());

}

}

我们定义了两个线程,每个线程跑10000次,我们希望看到的结果是20000,可打印出的结果小于20000。

问题解决

这个他哪里写错了,怎么去解决这个问题?

加锁

public class CounterBasic implements Counter {

volatile int i=0;

@Override

public synchronized int incr() {

return i++;

}

@Override

public synchronized int decr() {

return i--;

}

@Override

public int get() {

return i;

}

}

Aqs解决办法

public class CounterBasic implements Counter {

volatile int i=0;

Lock lock=new ReentrantLock();

@Override

public int incr() {

lock.lock();

try{

return i++;

} finally {

lock.unlock();

}

}

@Override

public int decr() {

lock.lock();

try{

return i--;

}finally {

lock.unlock();

}

}

@Override

public int get() {

return i;

}

}

原子整型

AtomicInteger i=new AtomicInteger (0);

底层原理

上面的基础面试我就把那个人淘汰了,知道为什么会出现这个问题么?

这样分析jvm执行过程,从源码到字节码去分析。Idea中引入jclasslib插件。我们打印出汇编指令。aload,dump,iconst_1,iadd。

Jmm数据原子操作

read(读取):从主内存读数据。

Load(载入):将主内存读取到的数据写入工作内存。

Use(使用):从工作内存读取数据来计算。

Assign(赋值):将计算好的值重新赋值到工作内存中。

Write(写入):将store过去的变量赋值给主内存的变量。

Lock(锁定):将主内存变量加锁,标识为线程独占状态。

Unlock(解锁):将主内存变量解锁,解锁后其它线程可以锁定该变量。

线程1回写主内存在store的时候,通过监听嗅探机制其它线程失效掉,如果第二个线程执行变量加一,没有store回主线程,就嗅探机制了,那它的加一操作就丢失掉了。

如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并将共享资源设置为锁定状态,如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制AQS是用CLH队列锁实现的,即将暂时获取不到锁的线程加入到队列中。

CAS 机制

即compare and swap,属于硬件同步原语,处理器提供了基本内存操作的原子性保证。底层cas需要输入两个参数:旧值A和新值B,在操作时候先比较输入的救值A和内存中是否一致,不一致代表内存数据发生了变化,cas失败。

如果输入的旧值A和内存的数据一致,则将值A替换成值B,cas操作成功。

如果觉得《一道面试题验出JAVA多线程功底 深入浅出多线程 进来看看》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。