LeetCode刷题之旅【多线程篇-2】中等: 1195. 交替打印字符串

本文详细解析了LeetCode上的经典多线程问题——FizzBuzz的三种解决方案,包括使用锁确保操作原子性、利用CyclicBarrier同步线程以及通过共享变量和同步代码块实现线程间协作,为读者提供了深入理解多线程编程技巧的机会。

2019年11月18日

原题:https://leetcode-cn.com/problems/fizz-buzz-multithreaded/

目录 交替打印字符串

题目

解题1

解题2

解题3


题目 交替打印字符串

 

解题1

加锁确保操作原子性,AtomicInteger 确保原子性


class FizzBuzz {
	private int n;
	private Object lock = new Object();
	AtomicInteger count = new AtomicInteger(1);

	public FizzBuzz(int n) {
		this.n = n;
	}

	// printFizz.run() outputs "fizz".
	// 线程A将调用 fizz() 来判断是否能被 3 整除,如果可以,则输出 fizz。
	public void fizz(Runnable printFizz) throws InterruptedException {
		while (count.get() <= n){
			synchronized (lock){
				if (count.get() <= n && count.get() % 3 == 0 && count.get() % 5 != 0){
					printFizz.run();
					count.incrementAndGet();
				}
			}

		}

	}

	// printBuzz.run() outputs "buzz".
	// 线程B将调用 buzz() 来判断是否能被 5 整除,如果可以,则输出 buzz。
	public void buzz(Runnable printBuzz) throws InterruptedException {
		while (count.get() <= n){
			synchronized (lock){
				if (count.get() <= n && count.get() % 5 == 0 && count.get() % 3 != 0){
					printBuzz.run();
					count.incrementAndGet();
				}
			}
		}
	}

	// printFizzBuzz.run() outputs "fizzbuzz".
	// 线程C将调用 fizzbuzz() 来判断是否同时能被 3 和 5 整除,如果可以,则输出 fizzbuzz。
	public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
		while (count.get() <= n){
			synchronized (lock){
				if (count.get() <= n && (count.get() % 5 == 0 && count.get() % 3 == 0)){
					printFizzBuzz.run();
					count.incrementAndGet();
				}
			}
		}
	}

	// printNumber.accept(x) outputs "x", where x is an integer.
	// 线程D将调用 number() 来实现输出既不能被 3 整除也不能被 5 整除的数字。
	public void number(IntConsumer printNumber) throws InterruptedException {
		while (count.get() <= n){
			synchronized (lock){
				if (count.get() <= n && (count.get() % 5 != 0 && count.get() % 3 != 0)){
					printNumber.accept(count.get());
					count.incrementAndGet();
				}
			}
		}
	}
}

 

解题2

一个网友角度新颖的解题方法:体现了Java并发包工具的方便。设立static(静态唯一)的CyclicBarrier(等待其他线程都一起触发之后,才进行下一步操作。)。


class FizzBuzz {
    private int n;
 private static CyclicBarrier barrier = new CyclicBarrier(4);

    public FizzBuzz(int n) {
        this.n = n;
    }

    // printFizz.run() outputs "fizz".
    public void fizz(Runnable printFizz) throws InterruptedException {
        for (int i = 1; i <= n; i++) {
            if (i % 3 == 0 && i % 5 != 0) {
                printFizz.run();
            }
            try {
                barrier.await();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }

    // printBuzz.run() outputs "buzz".
    public void buzz(Runnable printBuzz) throws InterruptedException {
        for (int i = 1; i <= n; i++) {
            if (i % 3 != 0 && i % 5 == 0) {
                printBuzz.run();
            }
            try {
                barrier.await();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }

    // printFizzBuzz.run() outputs "fizzbuzz".
    public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
        for (int i = 1; i <= n; i++) {
            if (i % 3 == 0 && i % 5 == 0) {
                printFizzBuzz.run();
            }
            try {
                barrier.await();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public void number(IntConsumer printNumber) throws InterruptedException {
        for (int i = 1; i <= n; i++) {
            if (i % 3 != 0 && i % 5 != 0) {
                printNumber.accept(i);
            }
            try {
                barrier.await();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}

 

解题3

方法一:锁
分析:
设置一个每个线程共有的变量i,用来代表当前的数字
将每一个判断并打印的操作,放在一个同步代码块内部,以保证操作的原子性,使得所有操作串行发生
每一个线程内部,当i小于等于n时,不断的争用同一把锁。
当线程得到锁后,判断当前的数字i是否满足自身的打印条件,若是则打印,并将i+1,否则放弃这把锁。


class FizzBuzz {
    private int n;
    private int i;
    private Object lock = new Object();

    public FizzBuzz(int n) {
        this.n = n;
        this.i = 1;
    }

    // printFizz.run() outputs "fizz".
    public void fizz(Runnable printFizz) throws InterruptedException {
        while (i <= n) {
            synchronized(lock) {
                while (i <= n && i % 3 == 0 && i % 5 != 0) {
                    printFizz.run();
                    i++; 
                }
            }
        }
        
    }

    // printBuzz.run() outputs "buzz".
    public void buzz(Runnable printBuzz) throws InterruptedException {
        while (i <= n) {
            synchronized(lock) {
                while (i <= n && i % 3 != 0 && i % 5 == 0) {
                    printBuzz.run();
                    i++;
                } 
            }
        }
        
    }

    // printFizzBuzz.run() outputs "fizzbuzz".
    public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
        while (i <= n) {
            synchronized(lock) {
                while (i <= n && i % 3 == 0 && i % 5 == 0) {
                    printFizzBuzz.run();
                    i++;
                }
            }
        }
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public void number(IntConsumer printNumber) throws InterruptedException {
        while (i <= n) {
             synchronized(lock) {
                while (i <= n && i % 3 != 0 && i % 5 != 0) {
                    printNumber.accept(i);
                    i++; 
                }
            }
        }
       
    }
}

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

后台技术汇

对你的帮助,是对我的最好鼓励。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值