欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-05 15:15:56
...

2019年11月18日

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

目录 交替打印字符串

题目

解题1

解题2

解题3


题目 交替打印字符串

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

 

解题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();
				}
			}
		}
	}
}

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

 

解题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();
            }
        }
    }
}

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

 

解题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++; 
                }
            }
        }
       
    }
}

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