JUC即java.util.concurrent包,这个包下面提供很多用于保证多线程安全的类,比如atomic包下面的原子类、locks包下面和锁相关的类以及其他类。在这篇文章中,我们将讲解JUC下一些常用的类的基本使用。
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()方法尝试获取锁,如果获取失败可以继续执行其他的操作而不用一种阻塞等待。
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可以继续往下执行。
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个人才可以发车,周而复始。
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,可用于分阶段执行的事件处理。以上代码,描述了异常婚礼的过程:所有宾客和新郎新娘到齐 > 所有人吃完饭 > 宾客离开 > 新郎新娘抱抱,婚礼结束。
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提供了一个读写锁(也称为共享锁和排他锁)的机制,多个线程可以同时获取到读锁(共享锁),而同一时刻只能有一个线程获取到写锁(排他锁)。
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即为信号量,表示同时可以有多少个线程执行,其应用场景是限流。
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可用于两个线程之间交换数据,也是线程通信的一种方式。
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常用类的一些基本用法,关于其内部的具体实现和原理,将在后续内容中讲解,敬请期待。