喵星软件园提供热门手机游戏下载,最新手机游戏攻略!

Waitress好玩吗 Waitress玩法简介,waitress攻略

时间:2023-10-05 09:41:40 来源: 浏览:

面试官跟我扯了半小时 CountDownLatch 后,给我发 Offer?| 原力计划

作者 | 万猫学社

责编 | 王晓曼

出品 | CSDN博客

一个长头发、穿着清爽的小姐姐,拿着一个崭新的Mac笔记本向我走来,看着来势汹汹,我心想着肯定是技术大佬吧!但是我也是一个才华横溢的人,稳住我们能赢。

面试官:看你简历上有写熟悉并发编程,CountDownLatch一定用过吧,跟我说说它!:CountDownLatch是JDK提供的一个同步工具,它可以让一个或多个线程等待,一直等到其他线程中执行完成一组操作。面试官:CountDownLatch有哪些常用的方法?:有CountDown方法和Await方法,CountDownLatch在初始化时,需要指定用给定一个整数作为计数器。当调用CountDown方法时,计数器会被减1;当调用Await方法时,如果计数器大于0时,线程会被阻塞,一直到计数器被CountDown方法减到0时,线程才会继续执行。计数器是无法重置的,当计数器被减到0时,调用Await方法都会直接返回。面试官调用CountDown方法时,线程也会阻塞嘛?:不会的,调用CountDown的线程可以继续执行,不需要等待计数器被减到0,只是调用Await方法的线程需要等待。面试官:可以举一个使用CountDownLatch的例子吗?:比如张三、李四和王五几个人约好去饭店一起去吃饭,这几个人都是比较绅士,要等到所有人都到齐以后才让服务员上菜。这种场景就可以用到CountDownLatch。面试官:可以写一下吗?

我:当然可以,这是张三、李四和王五的顾客类:

package onemore.study;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.CountDownLatch;

public class Customer implements Runnable {
private CountDownLatch latch;
private String name;

public Customer(CountDownLatch latch, String name) {
this.latch = latch;
this.name = name;
}

@Override
public void run {
try {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
Random random = new Random;

System.out.println(sdf.format(new Date) + " " + name + "出发去饭店");
Thread.sleep((long) (random.nextDouble * 3000) + 1000);
System.out.println(sdf.format(new Date) + " " + name + "到了饭店");
latch.countDown;
} catch (Exception e) {
e.printStackTrace;
}
}
}

这是服务员类:

package onemore.study;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.concurrent.CountDownLatch;

public class Waitress implements Runnable {

private CountDownLatch latch;

private String name;

public Waitress(CountDownLatch latch, String name) {

this.latch = latch;

this.name = name;

}

@Override

public void run {

try {

SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");

System.out.println(sdf.format(new Date) + " " + name + "等待顾客");

latch.await;

System.out.println(sdf.format(new Date) + " " + name + "开始上菜");

} catch (Exception e) {

e.printStackTrace;

}

}

}

然后,再写一个测试类,用于模拟上面所说的场景:

package onemore.study;

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.CountDownLatch;

public class CountDownLatchTester {

public static void main(String<> args) throws InterruptedException {

CountDownLatch latch = new CountDownLatch(3);

List<Thread> threads = new ArrayList<>(3);

threads.add(new Thread(new Customer(latch, "张三")));

threads.add(new Thread(new Customer(latch, "李四")));

threads.add(new Thread(new Customer(latch, "王五")));

for (Thread thread : threads) {

thread.start;

}

Thread.sleep(100);

new Thread(new Waitress(latch, "♥小芳♥")).start;

}

}

运行以后的结果应该是这样的:

15:25:53.015 王五出发去饭店

15:25:53.015 李四出发去饭店

15:25:53.015 张三出发去饭店

15:25:53.062 ♥小芳♥等待顾客

15:25:54.341 张三到了饭店

15:25:54.358 李四到了饭店

15:25:56.784 王五到了饭店

15:25:56.784 ♥小芳♥开始上菜

可以看到,服务员小芳在调用Await方法时一直阻塞着,一直等到三个顾客都调用了CountDown方法才继续执行。

面试官:如果有一个顾客迟迟没到,饭店都打样了,也不能一直等啊,应该这么办?:可以使用Await方法的另一个重载,传入等待的超时时间,比如服务员只等3秒钟,可以把服务员类中的:

latch.await;

改成:

latch.await(3, TimeUnit.SECONDS);

运行结果可能是这样的:

17:24:40.915 张三出发去饭店

17:24:40.915 李四出发去饭店

17:24:40.915 王五出发去饭店

17:24:40.948 ♥小芳♥等待顾客

17:24:43.376 李四到了饭店

17:24:43.544 王五到了饭店

17:24:43.951 ♥小芳♥开始上菜

17:24:44.762 张三到了饭店

可以看到,服务员小芳在调用Await方法时虽然被阻塞了,但是时间超过3秒后,没等顾客张三调用CountDown方法就继续执行开始上菜了。

面试官:CountDownLatch的实现原理是什么?:CountDownLatch有一个内部类叫做Sync,它继承了AbstractQueuedSynchronizer类,其中维护了一个整数state,并且保证了修改state的可见性和原子性。

创建CountDownLatch实例时,也会创建一个Sync的实例,同时把计数器的值传给Sync实例,具体是这样的:

public CountDownLatch(int count) {

if (count < 0) throw new IllegalArgumentException("count < 0");

this.sync = new Sync(count);

}

CountDown方法中,只调用了Sync实例的ReleaseShared方法,具体是这样的:

public void countDown {

sync.releaseShared(1);

}

其中的ReleaseShared方法,先对计数器进行减1操作,如果减1后的计数器为0,唤醒被Await方法阻塞的所有线程,具体是这样的:

public final boolean releaseShared(int arg) {

if (tryReleaseShared(arg)) { //对计数器进行减一操作

doReleaseShared;//如果计数器为0,唤醒被await方法阻塞的所有线程

return true;

}

return false;

}

其中的TryReleaseShared方法,先获取当前计数器的值,如果计数器为0时,就直接返回;如果不为0时,使用CAS方法对计数器进行减1操作,具体是这样的:

protected boolean tryReleaseShared(int releases) {

for (;;) {//死循环,如果CAS操作失败就会不断继续尝试。

int c = getState;//获取当前计数器的值。

if (c == 0)// 计数器为0时,就直接返回。

return false;

int nextc = c-1;

if (compareAndSetState(c, nextc))// 使用CAS方法对计数器进行减1操作

return nextc == 0;//如果操作成功,返回计数器是否为0

}

}

在Await方法中,只调用了Sync实例的AcquireSharedInterruptibly方法,具体是这样的:

public void await throws InterruptedException {

sync.acquireSharedInterruptibly(1);

}

其中AcquireSharedInterruptibly方法,判断计数器是否为0,如果不为0则阻塞当前线程,具体是这样的:

public final void acquireSharedInterruptibly(int arg)

throws InterruptedException {

if (Thread.interrupted)

throw new InterruptedException;

if (tryAcquireShared(arg) < 0)//判断计数器是否为0

doAcquireSharedInterruptibly(arg);//如果不为0则阻塞当前线程

}

其中TryAcquireShared方法,是AbstractQueuedSynchronizer中的一个模板方法,其具体实现在Sync类中,其主要是判断计数器是否为零,如果为零则返回1,如果不为零则返回-1,具体是这样的:

protected int tryAcquireShared(int acquires) {

return (getState == 0) ? 1 : -1;

}

面试官:嗯,很不错,马上给你发Offer。

版权声明:本文为CSDN博主「万猫学社」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/heihaozi/article/details/105738230

☞芯片供应被掐断,华为能否安全渡劫?

☞OceanBase 十年:一群追梦人的成长史

☞2 年 6 个月 11 天,外包到阿里的修仙之路!| 原力计划

☞服务器软件大扫盲!

☞绝悟之后再超神,腾讯30篇论文入选AI顶会ACL

☞中本聪并没有出现,那真相是?

标题:Waitress好玩吗 Waitress玩法简介,waitress攻略
链接:https://www.miaoshengapp.cn/yxgl/125291.html
版权:文章转载自网络,如有侵权,请联系删除!
资讯推荐
《收纳物语》游戏沐浴清晨通关方法一览
《收纳物语》游戏沐浴清晨通关方法一览

《收纳物语》是上很火爆的休闲解压的小游戏

2022-12-23
原神班尼特武器圣遗物在哪刷
原神班尼特武器圣遗物在哪刷

很多玩家小伙伴不是很清楚,原神班尼特武器圣

2022-12-22
开罗拉面店食谱配方一览 开罗拉面店拉面制作攻略
开罗拉面店食谱配方一览 开罗拉面店拉面制作攻略

一款像素风餐厅经营手游近期受到玩家们关注

2023-06-09
《幻塔》奥特怎么样 奥特介绍,
《幻塔》奥特怎么样 奥特介绍,

《幻塔》弗丽嘉拟态介绍 巴尔蒙克使用攻略

2023-10-04
这就是江湖双峰找人全角色攻略
这就是江湖双峰找人全角色攻略

这就是江湖双峰找人全角色攻略,这就是江湖游

2023-05-29
《天命奇御2》刀法怎么选 刀法强度排名榜分享,天命奇御2刀法天赋选择
《天命奇御2》刀法怎么选 刀法强度排名榜分享,天命奇御2刀法天赋选择

什么值得玩:推荐十款2019玩过的游戏2019年玩

2023-10-04