多线程 -- 交替打印

输入一个数字n,交替打印foobar n 次

public static void main(String[] args) {
    int n = 10; //打印次数
    FooBar fooBar = new FooBar(n);
    Runnable printFoo = () -> {
        System.out.print("foo");
    };
    Runnable printBar = () -> {
        System.out.print("bar");
    };
    Thread fooThread = new Thread(() -> {
        try {
            fooBar.foo(printFoo);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    Thread barThread = new Thread(() -> {
        try {
            fooBar.bar(printBar);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    fooThread.start();
    barThread.start();
}

1. ReentrantLock

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class FooBar {
	private int n;
	private volatile boolean bl;
	private Lock lock = new ReentrantLock();
	private Condition condition = lock.newCondition();

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

	public void foo(Runnable printFoo) throws InterruptedException {
		for (int i = 0; i < n; i++) {
			lock.lock();
			try {
				while (bl) { //当false时输出foo,否则在这里阻塞
					condition.await();
				}
				// printFoo.run() outputs "foo".
				printFoo.run();
				bl = true;
				condition.signal();
			} finally {
				lock.unlock();
			}

		}
	}

	public void bar(Runnable printBar) throws InterruptedException {
		for (int i = 0; i < n; i++) {
			lock.lock();
			try {
				while (!bl) { //当true时输出bar,否则在这里阻塞
					condition.await();
				}
				// printBar.run() outputs "bar".
				printBar.run();
				bl = false;
				condition.signal();
			} finally {
				lock.unlock();
			}
		}
	}
}

2. 使用信号量Semaphore

class FooBar {
	private int n;
	
	private Semaphore fooSemaphore = new Semaphore(1); //控制输出foo
	private Semaphore barSemaphore = new Semaphore(0); //控制输出bar

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

	public void foo(Runnable printFoo) throws InterruptedException {
		for (int i = 0; i < n; i++) {
			fooSemaphore.acquire(); //可以认为需要得到这个信号量才能进行下一步,不然就阻塞
			printFoo.run();
			barSemaphore.release(); //将信号量+1
		}
	}

	public void bar(Runnable printBar) throws InterruptedException {
		for (int i = 0; i < n; i++) {
			barSemaphore.acquire();
			printBar.run();
			fooSemaphore.release();
		}
	}
}

3. 使用CyclicBarrier (与CountDownLatch 的主要区别是CyclicBarrier 可以重复使用)

class FooBar {
	private int n;
	private volatile boolean bl;

	private CyclicBarrier cb = new CyclicBarrier(2);

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

	public void foo(Runnable printFoo) throws InterruptedException {
		for (int i = 0; i < n; i++) {
			while(bl) { //当是true时, 进行空转或者让出, false时打印foo
                Thread.yield();
            }
            printFoo.run();
			bl = true;
			try {
				cb.await(); //将foo线程进行同步,相当于-1,然后阻塞当前线程
			} catch (BrokenBarrierException e) {
				e.printStackTrace();
			}
		}
	}

	public void bar(Runnable printBar) throws InterruptedException {
		for (int i = 0; i < n; i++) {
			try {
				cb.await(); //将bar线程同步
			} catch (BrokenBarrierException e) {
				e.printStackTrace();
			}
			printBar.run();
			bl = false;
		}
	}
}

4. 用Thread.yield(),让出CPU,具体还是得看线程的调度

class FooBar {
	private int n;
	private volatile boolean bl;

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

	public void foo(Runnable printFoo) throws InterruptedException {
		for (int i = 0; i < n;) {
			if (!bl) {
				printFoo.run();
				bl = true;
				i++;
			} else { //让出这一轮循环,等待重新进入循环
				Thread.yield();
			}
		}
	}

	public void bar(Runnable printBar) throws InterruptedException {
		for (int i = 0; i < n;) {
			if (bl) {
				printBar.run();
				bl = false;
				i++;
			} else {
				Thread.yield();
			}
		}
	}
}

5. BlockingQueue

class FooBar {
	private int n;
	
	private BlockingQueue<Integer> fooQueue = new LinkedBlockingDeque<>();
	private BlockingQueue<Integer> barQueue = new LinkedBlockingDeque<>(); 
	
	public FooBar(int n) {
		this.n = n;
		fooQueue.add(0); //做为第一个输出
	}

	public void foo(Runnable printFoo) throws InterruptedException {
		for (int i = 0; i < n; i++) {
			fooQueue.take(); //取出队头元素,如果队列为空则阻塞
			printFoo.run();
			barQueue.add(0);
		}
	}

	public void bar(Runnable printBar) throws InterruptedException {
		for (int i = 0; i < n; i++) {
			barQueue.take();
			printBar.run();
			fooQueue.add(0);
		}
	}
}

6.使用Synchronized,配合wait和notify进行线程的控制

class FooBar {
	private int n;
	private volatile boolean bl;
	private Object lock = new Object();

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

	public void foo(Runnable printFoo) throws InterruptedException {
		for (int i = 0; i < n; i++) {
			synchronized (lock) {
				if (bl) {
					lock.wait();
				}
				printFoo.run();
				bl = true;
				lock.notify();
			}
		}
	}

	public void bar(Runnable printBar) throws InterruptedException {
		for (int i = 0; i < n; i++) {
			synchronized (lock) {
				if (!bl) {
					lock.wait();
				}
				printBar.run();
				bl = false;
				lock.notify();
			}
		}
	}
}

7.使用LockSupport,方式上类似于Synchronized

多线程 -- 交替打印

上一篇:JavaScript的安全性问题(js不能做什么)--来自新浪勇敢的心的博客


下一篇:PHP条件语句语法与示例