JUC使用案例

前言

  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常用类的一些基本用法,关于其内部的具体实现和原理,将在后续内容中讲解,敬请期待。

版权声明:玥玥 发表于 2021-04-23 23:17:21。
转载请注明:JUC使用案例 | 女黑客导航