跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 求一个 Java 面试题的最佳实践
未分類
25 1 月 2021

求一个 Java 面试题的最佳实践

求一个 Java 面试题的最佳实践

資深大佬 : Cbdy 5

三个线程,分别输出 a 、b 、c,各输出 100 次,要求按 abc 的顺序输出

期待输出为:abcabcabcabc…

大佬有話說 (46)

  • 資深大佬 : Yi23

    第一反应可以使用 lock.condition 实现,3 个线程每个线程打印自己的字符,然后唤醒下一个线程。
    线程 1 的方法类似如下
    类似这样
    “`
    lock.lock();
    while (n != a) {
    condition1.await(); // 线程 1 阻塞
    }
    // 输出 n
    n = b; // 修改 n=b 然后唤醒线程 2
    condition2.signal();
    lock.unlock();
    “`

  • 資深大佬 : chenshun00

    public static void main(String[] args) {

    final Object xx1 = new Object();
    final Object xx2 = new Object();
    final Object xx3 = new Object();
    Thread a = new Thread(() -> {

    try {
    synchronized (xx1) {
    xx1.wait();
    }
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    int a1 = 0;
    while (a1 < 100) {
    System.out.print(“a”);
    a1++;

    synchronized (xx2) {
    xx2.notify();
    }
    try {
    synchronized (xx1) {
    xx1.wait();
    }
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    });
    a.setDaemon(true);
    a.setName(“aaa”);
    Thread b = new Thread(() -> {
    try {
    synchronized (xx2) {
    xx2.wait();
    }
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    int b1 = 0;
    while (b1 < 100) {
    System.out.print(“b”);
    b1++;
    synchronized (xx3) {
    xx3.notify();
    }
    try {
    synchronized (xx2) {
    xx2.wait();
    }
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    });
    b.setDaemon(true);
    b.setName(“bbb”);
    Thread c = new Thread(() -> {
    try {
    synchronized (xx3) {
    xx3.wait();
    }
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    int c1 = 0;
    while (c1 < 100) {
    System.out.println(“c”);
    c1++;
    synchronized (xx1) {
    xx1.notify();
    }
    try {
    synchronized (xx3) {
    xx3.wait();
    }
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    });
    c.setDaemon(true);
    c.setName(“ccc”);
    a.start();
    b.start();
    c.start();

    synchronized (xx1) {
    xx1.notify();
    }

    try {
    Thread.sleep(100L);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }

    }

  • 資深大佬 : mawerss1

    public class Volatile implements Runnable{

    private volatile int state = 0;

    public static void main(String[] args) throws InterruptedException {
    for (int i = 0; i < 3; i++) {
    Thread thread = new Thread(new Volatile());
    thread.start();
    thread.join();
    }
    }

    @Override
    public void run() {
    int count = 0;
    while (true) {
    if (count >= 100) {
    break;
    }
    if (state == 0) {
    System.out.println(“a”);
    state = 1;
    }
    if (state == 1) {
    System.out.println(“b”);
    state = 2;
    }
    if (state == 2) {
    System.out.println(“c”);
    state = 0;
    }
    count++;
    }
    }
    }

  • 資深大佬 : chenshun00

    @mawerss1 好像偏题了

  • 資深大佬 : mytudan

    class Abc {
    private int n;
    // 标志位,控制执行顺序,0 执行 a,1 执行 b 2 执行 c
    private volatile int type;
    // 锁标志
    private final Object object;

    public Abc(int n) {
    this.n = n;
    object = new Object();
    type = 0;
    }

    public void a(Runnable a) throws InterruptedException {
    for (int i = 0; i < n; i++) {
    synchronized (object) {
    while (!(type == 0)) {
    object.wait();
    }
    a.run();
    type = 1;
    object.notifyAll();
    }
    }
    }

    public void b(Runnable b) throws InterruptedException {
    for (int i = 0; i < n; i++) {
    synchronized (object) {
    while (!(type == 1)) {
    object.wait();
    }
    b.run();
    type = 2;
    object.notifyAll();
    }
    }
    }

    public void c(Runnable c) throws InterruptedException {
    for (int i = 0; i < n; i++) {
    synchronized (object) {
    while (!(type == 2)) {
    object.wait();
    }
    c.run();
    type = 0;
    object.notifyAll();
    }
    }
    }

    }

  • 資深大佬 : mawerss1

    @chenshun00 哈哈 全错了

  • 資深大佬 : chendy

    生产者-消费者模型
    a 生产 b 消费,b 生产 c 消费,c 生产 a 消费

  • 資深大佬 : leafre

    ReentrantLock

  • 資深大佬 : hitmanx

    把它看成三个独立的生产者消费者,用独立的 sync objects

  • 資深大佬 : woshiaha

    老题了 用一个原子数当锁 每次有输出原子数都加一 抢到锁才可以输出
    a 线程只在原子数%3 为 0 时输出
    b 线程只在原子数%3 为 1 时输出
    c 线程只在原子数%3 为 2 时输出

  • 資深大佬 : mytudan

    我上面那个是照着 leetcode 上的题改的

  • 資深大佬 : mawerss1

    @chenshun00 state 变量改成 static,join 方法删掉,改成用 CountDownLatch

  • 資深大佬 : yazinnnn

    有个问题,这个多线程有什么意义?

  • 資深大佬 : Vendettar

    “`java
    public static void main(String[] args) {
    ReentrantLock lock = new ReentrantLock(true);
    for (int i = 0; i < 3; i++) {
    int order = i;
    new Thread(()->{
    for (int j = 0; j < 100; j++) {
    lock.lock();
    System.out.println(Thread.currentThread().getName() + “:” + (char)(‘a’+order));
    lock.unlock();
    }
    }, “Thread-” + i).start();
    }
    }
    “`

  • 資深大佬 : Vendettar

    直接一个公平锁 new ReentrantLock(true)按顺序来就可以

  • 資深大佬 : Takamine

    刚撸的一个,应该算是比较传统的解法吧。
    https://paste.ubuntu.com/p/zbDMK6qJQm/

  • 資深大佬 : micean

    每个线程调用这个类就行了
    class ABCPrinter{
    int[] arr = new int[]{0, 0, 0};
    int i = 0;

    public synchronized void addChar(char ch){
    arr[(int)(ch – ‘a’)]++;
    print();
    }

    void print(){
    while(arr[i] > 0){

    打印((char)(arr[i] + ‘a’));
    arr[i]–;
    i = (i + 1)%3

    }
    }

    }

  • 資深大佬 : ocean1477

    @Vendettar 直接不对。

  • 資深大佬 : Rorysky

    synchronized 一把梭

  • 資深大佬 : Vendettar

    @ocean1477 咋不对呢 我这里输出是对的啊..

  • 資深大佬 : ocean1477

    @Vendettar 这个是无法保证顺序的,1,2,3 三个线程可以同时进,争抢一个锁。

  • 資深大佬 : Vendettar

    @ocean1477 公平锁不会争抢 你输出一下试试 顺序不会乱

  • 資深大佬 : ocean1477

    @Vendettar 我这会试了下,会乱的,多试几次。
    Thread-0:a
    Thread-0:a
    Thread-0:a
    Thread-0:a
    Thread-0:a
    Thread-1:b
    Thread-2:c
    Thread-0:a
    Thread-1:b
    Thread-2:c
    Thread-0:a
    Thread-1:b
    Thread-2:c
    Thread-0:a
    Thread-1:b

  • 資深大佬 : ocean1477

    @Vendettar 看来老兄要重新看下公平锁了,公平锁≠顺序

  • 資深大佬 : Vendettar

    @ocean1477 热 我试出来了 的确会乱

  • 資深大佬 : ocean1477

    @Vendettar 哈哈,我无意指出,抱歉。

  • 資深大佬 : ssynhtn

    用三个 Semaphore 就行了吧

  • 資深大佬 : Vendettar

    @ocean1477 感谢指出

  • 資深大佬 : sczero

    public static void main(String[] args) throws InterruptedException {
    final AtomicReference<String> tag = new AtomicReference<>(“a”);
    final int total = 100;
    new Thread(() -> {
    int count = 0;
    while (count < total) {
    if (tag.get().equals(“a”)) {
    System.out.print(“a”);
    tag.set(“b”);
    count++;
    }
    }
    }).start();
    new Thread(() -> {
    int count = 0;
    while (count < total) {
    if (tag.get().equals(“b”)) {
    System.out.print(“b”);
    tag.set(“c”);
    count++;
    }
    }
    }).start();
    new Thread(() -> {
    int count = 0;
    while (count < total) {
    if (tag.get().equals(“c”)) {
    System.out.println(“c”);
    tag.set(“a”);
    count++;
    }
    }
    }).start();
    }

  • 資深大佬 : ssynhtn

    public static void main(String[] args) {
    Semaphore[] res = {
    new Semaphore(1),
    new Semaphore(0),
    new Semaphore(0),
    };

    for (int i = 0; i < 3; i++) {
    Semaphore current = res[i];
    Semaphore next = res[(i + 1) % 3];
    final char ch = (char) (i + ‘a’);
    new Thread(new Runnable() {
    @Override
    public void run() {
    for (int j = 0; j < 100; j++) {
    try {
    current.acquire();
    System.out.print(ch);
    next.release();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }

    }
    }
    }).start();
    }

    }

  • 資深大佬 : Cyron

    简单公平锁实现
    “`
    public class ReentrantLockDemo implements Runnable {

    private static ReentrantLock lock = new ReentrantLock(true);

    private String content;

    public ReentrantLockDemo(String content) {
    this.content = content;
    }

    @Override
    public void run() {
    while (true) {
    try {
    lock.lock();
    System.out.println(content);
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    } finally {
    lock.unlock();
    }
    }
    }

    public static void main(String[] args) {
    ReentrantLockDemo a = new ReentrantLockDemo(“a”);
    ReentrantLockDemo b = new ReentrantLockDemo(“b”);
    ReentrantLockDemo c = new ReentrantLockDemo(“c”);
    Thread threadA = new Thread(a);
    Thread threadB = new Thread(b);
    Thread threadC = new Thread(c);
    threadA.start();
    threadB.start();
    threadC.start();
    }
    }
    “`

  • 資深大佬 : zzh7982

    不用加锁,join 就行了,刚测试了一把 没问题

    https://gist.github.com/zzh7982/249883f379b50c5ae50eacd48736b5e2

  • 資深大佬 : kikione

    我想到两个方案,第一个是加锁。 第二个是 join,b 等 a ,c 等 a 。

  • 資深大佬 : sczero

    @zzh7982 新建了 300 个线程……至于吗….

  • 資深大佬 : zzh7982

    @sczero 啊..这… 300 个线程都能控制顺序 这不显得水平高吗[dog]

  • 資深大佬 : kikione

    for (int i=0;i<100;i++){
    Thread1 thread1 = new Thread1();
    Thread2 thread2 = new Thread2();
    Thread3 thread3 = new Thread3();
    thread1.start();
    thread1.join();
    thread2.start();
    thread2.join();
    thread3.start();
    }

  • 資深大佬 : sampeng

    都是有锁方案啊。。我提一个无锁和竞争的方案
    三个队列。分别收 a,b,c 。
    输出就是轮询这 3 个队列就好了。。一定都是有序的

  • 資深大佬 : johnson666

    原子变量

    public class Test {
    public static void main(String[] args) {
    AtomicInteger at = new AtomicInteger();
    for (int i = 0; i < 3; i++) {
    MyThread t = new MyThread(at, i);
    t.start();
    }
    }
    }

    class MyThread extends Thread {
    private AtomicInteger at;
    private int index;

    public MyThread(AtomicInteger at, int index) {
    this.at = at;
    this.index = index;
    }

    @Override
    public void run() {
    while(true) {
    if(at.get() % 3 == index) {
    System.out.print((char)(‘a’ + index));
    at.incrementAndGet();
    }
    }
    }
    }

  • 資深大佬 : Youen

    https://leetcode.com/problems/fizz-buzz/

  • 資深大佬 : YoongRii

    用原子变量%3 这种解法比较常见,但是需要线程忙等,提供一种用线程池方式实现的思路:

    public static void main(String[] args) throws InterruptedException {
    ExecutorService executorService1 = Executors.newSingleThreadExecutor();
    ExecutorService executorService2 = Executors.newSingleThreadExecutor();
    ExecutorService executorService3 = Executors.newSingleThreadExecutor();

    Runnable[] rs = new Runnable[3];

    rs[0] = () -> {
    System.out.println(“A”);
    executorService2.submit(rs[1]);
    };

    rs[1] = () -> {
    System.out.println(“B”);
    executorService2.submit(rs[2]);
    };

    rs[2] = new Runnable() {
    private int a = 1;

    public void run() {
    System.out.println(“C”);
    if (a++ < 100)
    executorService3.submit(rs[0]);
    }
    };

    executorService1.submit(rs[0]);
    }

  • 資深大佬 : donggexiongdi

    public void printAbc(int count) {
    for (int i = 0; i < count; i++) {
    CompletableFuture.runAsync(() -> {
    System.out.println(“A”);
    }).thenRun(() -> {
    System.out.println(“B”);
    }).thenRun(() -> {
    System.out.println(“C”);
    });
    System.out.println(“——-“);
    }
    }

  • 資深大佬 : donggexiongdi

    我擦 不对

  • 資深大佬 : cubecube

    @sampeng
    1.队列也需要锁,无锁队列的话,如果某个线程输入太慢,跟不上,consumer 也得等待?
    2.另外,题目说得三个线程个,consumer 还得偷线程或者揉进到生产者线程的执行过程中。

    以上条件要全写对,比状态量的复杂。

  • 資深大佬 : sampeng

    @cubecube
    1.我说的无所锁方案是代码不需要明确的写锁的逻辑。也是一个比较自然的做法。而且队列的这种方式并没有资源竞争,只是 consumer 等待而已。
    2.三个线程难道就不能有主线程了?谁起的这 3 个线程呢?当然是主线程上直接循环啊。又不是生产环境。

  • 資深大佬 : Vendettar

    @Cyron 三个线程首次启动抢锁的话(3 线程都没有 sleep 过),a 抢 1b 抢 2 就没问题,如果 b 抢 1 那后面 99 次都是 b 先输出了

  • 資深大佬 : fantastM

    #10 说的方案是可行的,并且是基于 CAS 无锁的

    https://gist.github.com/fantasticmao/f78ae0016a81877cf5019d9c22c81c73

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具