JUC使用案例

文章目录

  • 前言
  • ReentranLock
  • CountDownLatch
  • CyclicBarrier
  • Phaser
  • ReadWriteLock
  • Semaphore
  • Exchanger
  • LockSupport
  • 总结

前言

  JUC即java.util.concurrent包,这个包下面提供很多用于保证多线程安全的类,比如atomic包下面的原子类、locks包下面和锁相关的类以及其他类。在这篇文章中,我们将讲解JUC下一些常用的类的基本使用。

ReentranLock

	public static void testReentrantLock() {
     
		Lock lock = new ReentrantLock();
		new Thread(() -> {
     
			try {
     
				lock.lock();
				Sleep.sleep(5);
				System.out.println("t1 end...");
			} finally {
     
				lock.unlock();
			}
		}).start();

		Sleep.sleep(1);
		new Thread(() -> {
     
			if (lock.tryLock()) {
     
				try {
     
					System.out.println("tryLock succ");
				} finally {
     
					lock.unlock();
				}
			} else {
     
				System.out.println("tryLock fail");
			}
		}).start();
	}

  ReentranLock需要手动调用lock()方法进行加锁,并且需要在finally块中调用unlock()方法释放锁,防止发生异常时出现死锁。除了lock()方法之外,ReentranLock还提供了tryLock()方法尝试获取锁,如果获取失败可以继续执行其他的操作而不用一种阻塞等待。

CountDownLatch

	public static void main(String[] args) {
     
		CountDownLatch latch = new CountDownLatch(1);
		new Thread(() -> {
     
			Sleep.sleep(2);
			latch.countDown();
		}).start();

		System.out.println("线程开始");
		latch.await();
		System.out.println("2s之后,countDown");
	}

  一个线程A可使用CountDownLatch.await()方法阻塞等待,其他线程可调用CountDownLatch.countDown()方法使CountDownLatch数值减1,当CountDownLatch数值为0的时候,线程A可以继续往下执行。

CyclicBarrier

	public void testCycleBarrie() {
     
		CyclicBarrier barrier = new CyclicBarrier(5, () -> {
     
			System.out.println("坐满了,发车!");
		});

		for (int i = 0; i < 10; i++) {
     
			new Thread(() -> {
     
				try {
     
					System.out.println(Thread.currentThread().getName() + "到达");
					barrier.await();
				} catch (InterruptedException e) {
     
					e.printStackTrace();
				} catch (BrokenBarrierException e) {
     
					e.printStackTrace();
				}
			}, "乘客" + i).start();
		}
	}

  以上代码模拟了这样一个场景,有一个辆客车,需要坐满5个人的时候才可以发车。客车出发后,下一辆车同样需要坐满5个人才可以发车,周而复始。

Phaser

public class TestPhaser {
     
	static Random r = new Random();
	static MarriagePhaser phaser = new MarriagePhaser();

	public static void main(String[] args) throws InterruptedException {
     
		phaser.bulkRegister(7);
		for (int i = 0; i < 5; i++) {
     
			new Person("person" + i).start();
		}
		new Person("新郎").start();
		new Person("新娘").start();
	}

	static class Person extends Thread {
     
		String name;

		public Person(String name) {
     
			this.name = name;
		}

		public void arrive() throws InterruptedException {
     
			Thread.sleep(r.nextInt(1000));
			System.out.printf("%s 到达现场!\n", name);
			phaser.arriveAndAwaitAdvance();
		}

		public void eat() throws InterruptedException {
     
			Thread.sleep(r.nextInt(1000));
			System.out.printf("%s 吃完!\n", name);
			phaser.arriveAndAwaitAdvance();
		}

		public void leave() throws InterruptedException {
     
			if (name.equals("新郎") || name.equals("新娘")) {
     
				phaser.arriveAndAwaitAdvance();
			} else {
     
				Thread.sleep(r.nextInt(1000));
				System.out.printf("%s 离开!\n", name);
				phaser.arriveAndAwaitAdvance();
			}
		}

		private void hug() throws InterruptedException {
     
			if (name.equals("新郎") || name.equals("新娘")) {
     
				Thread.sleep(r.nextInt(1000));
				System.out.printf("%s 抱抱!\n", name);
				phaser.arriveAndDeregister();
			} else {
     
				phaser.arriveAndDeregister();
			}
		}

		@Override
		public void run() {
     
			try {
     
				arrive();
				eat();
				leave();
				hug();
			} catch (InterruptedException e) {
     
				e.printStackTrace();
			}
		}
	}
}

class MarriagePhaser extends Phaser {
     
	@Override
	protected boolean onAdvance(int phase, int registeredParties) {
     
		switch (phase) {
     
		case 0:
			System.out.println("所有人到齐");
			System.out.println("----------");
			return false;
		case 1:
			System.out.println("所有人吃完");
			System.out.println("----------");
			return false;
		case 2:
			System.out.println("所有人离开");
			System.out.println("----------");
			return false;
		case 3:
			System.out.println("婚礼结束");
			System.out.println("----------");
			return true;
		default:
			return true;
		}
	}
}

  Phaser类似于升级版的CyclicBarrier,可用于分阶段执行的事件处理。以上代码,描述了异常婚礼的过程:所有宾客和新郎新娘到齐 > 所有人吃完饭 > 宾客离开 > 新郎新娘抱抱,婚礼结束。

ReadWriteLock

public static void testReanWriteLock() {
     
		ReadWriteLock lock = new ReentrantReadWriteLock();
		Lock readLock = lock.readLock ();
		Lock writeLock = lock.writeLock();

		for (int i = 0; i < 10; i++) {
     
			new Thread(() -> {
     
				readLock.lock();
				Sleep.sleep(2);
				System.out.println(Thread.currentThread().getName() + " read...");
				readLock.unlock();
			}, "Thread" + i).start();
		}

		for (int i = 10; i < 12; i++) {
     
			new Thread(() -> {
     
				writeLock.lock();
				Sleep.sleep(2);
				System.out.println(Thread.currentThread().getName() + " write...");
				writeLock.unlock();
			}, "Thread" + i).start();
		}
	}

  ReadWriteLock提供了一个读写锁(也称为共享锁和排他锁)的机制,多个线程可以同时获取到读锁(共享锁),而同一时刻只能有一个线程获取到写锁(排他锁)。

Semaphore

	public static void testSemaphore() {
     
		Semaphore semaphore = new Semaphore(1);
		new Thread(() -> {
     
			try {
     
				semaphore.acquire();
				System.out.println("线程1running");
				Thread.sleep(2000);
				System.out.println("线程1running");
			} catch (InterruptedException e) {
     
				e.printStackTrace();
			} finally {
     
				semaphore.release();
			}
		}).start();

		new Thread(() -> {
     
			try {
     
				semaphore.acquire();
				System.out.println("线程2running");
				Thread.sleep(2000);
				System.out.println("线程2running");
			} catch (InterruptedException e) {
     
				e.printStackTrace();
			} finally {
     
				semaphore.release();
			}
		}).start();
	}

  Semaphore即为信号量,表示同时可以有多少个线程执行,其应用场景是限流。

Exchanger

	public static void testExchanger() {
     
		Exchanger<String> exchanger = new Exchanger<>();
		new Thread(() -> {
     
			String name = "Tom";
			try {
     
				name = exchanger.exchange(name);
			} catch (InterruptedException e) {
     
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + " " + name);
		}, "t1").start();
		new Thread(() -> {
     
			String name = "Jack";
			try {
     
				name = exchanger.exchange(name);
			} catch (InterruptedException e) {
     
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + " " + name);
		}, "t2").start();
	}

输出:

t2 Tom
t1 Jack

  从上面的程序可以看出,线程t1和t2内部的变量name发生了交换。Exchanger可用于两个线程之间交换数据,也是线程通信的一种方式。

LockSupport

	public static void testLockSupport() throws InterruptedException {
     
		Thread t1 = new Thread(() -> {
     
			System.out.println("t1 start and park...");
			LockSupport.park();
			System.out.println("t1 continue and end...");
		}, "t1");
		t1.start();

		Thread.sleep(3000);
		System.out.println("3 second later, unpark t1");
		LockSupport.unpark(t1);
	}

  LockSupport相比于wait()和notify()更具有灵活性,notify()是随机唤醒一个正在等待的线程,而LockSupport可以唤醒一个特定的线程。

总结

  以上就是JUC常用类的一些基本用法,关于其内部的具体实现和原理,将在后续内容中讲解,敬请期待。

你可能感兴趣的:(JAVA多线程,java,多线程,并发编程,juc)