多线程工具类:CountDownLatch、CyclicBarrier、Semaphore、LockSupport


CountDownLatch

假如有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以。
比如你想要买套房子,但是呢你现在手上没有钱。你得等这个月工资发了、然后年终奖发了、然后朋友借你得钱还给你了、然后再给朋友借一部分才可以买,这种场景你就可以使用CountDownLatch。

CountDownLatch是JDK为我们提供的一个计数器,它的操作是原子操作,同一时间只能有一个线程去操作这个它。

我们先来看一下CountDownLatch的主要方法。

1
2
3
4
5
6
7
8
9
10
//构造方法,接收计数器的数量
public CountDownLatch(int count)
//持续等待计数器归零
public void await()
//最多等待unit时间单位内timeout时间
public boolean await(long timeout, TimeUnit unit)
//计数器减1
public void countDown()
//返回现在的计数器数量
public long getCount()

下面是CountDownLatch的基本使用示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class CountDownLatchDemo {
    public static CountDownLatch countDownLatch = new CountDownLatch(5);
    static class ThreadDemo extends Thread {
        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getId() + "完成任务");
            countDownLatch.countDown();
        }
    }
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 5; i++) {
            new ThreadDemo().start();
        }
        countDownLatch.await();
        System.out.println("全部完成任务");
    }
}


CyclicBarrier

相比较于CountDownLatch,CyclicBarrier可以完成前者的全部功能,但是相比前者,它的功能更加的强大。
CyclicBarrier翻译过来的中文名称叫循环栅栏,顾名思义它可以循环使用
CyclicBarrier还可以接收一个Runnable对象,当栅栏循环一次技术后会执行一次Runnable

我们来看一下CyclicBarrier的常用方法:

1
2
3
4
5
6
7
8
9
//构造方法,第一个参数为栅栏饿长度,第二个就是上方所说的Runnable对象
public CyclicBarrier(int parties, Runnable barrierAction)
public CyclicBarrier(int parties)
//获取现在的数量
public int getParties()
//持续等待栅栏归零
public int await()
//最多等待unit时间单位内timeout时间
public int await(long timeout, TimeUnit unit)

下面是CyclicBarrier的基本使用示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class CyclicBarrierDemo {
    public static CyclicBarrier cyclicBarrier = new CyclicBarrier(5,new FinallyThreadDemo());
    static class ThreadDemo extends Thread {
        @Override
        public void run() {
            try {
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getId() + "完成任务");
                cyclicBarrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            System.out.println("到达屏障点每个线程都会瞬时继续执行");
        }
    }
    static class FinallyThreadDemo extends Thread {
        @Override
        public void run() {
            System.out.println("所有任务已经完成之后单独执行的任务!");
        }
    }
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            new ThreadDemo().start();
        }
    }
}

观察打印结果我们可以发现:
当循环栅栏的任务执行完一轮以后,如果构造时传入了Runnable对象,则先执行Runnable对象,然后在瞬间释放所有任务的锁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
14完成任务
15完成任务
16完成任务
17完成任务
18完成任务
所有任务已经完成之后单独执行的任务!
到达屏障点每个线程都会瞬时继续执行
到达屏障点每个线程都会瞬时继续执行
到达屏障点每个线程都会瞬时继续执行
到达屏障点每个线程都会瞬时继续执行
到达屏障点每个线程都会瞬时继续执行
19完成任务
20完成任务
21完成任务
22完成任务
23完成任务
所有任务已经完成之后单独执行的任务!
到达屏障点每个线程都会瞬时继续执行
到达屏障点每个线程都会瞬时继续执行
到达屏障点每个线程都会瞬时继续执行
到达屏障点每个线程都会瞬时继续执行
到达屏障点每个线程都会瞬时继续执行


Semaphore

在 浅谈Java中的锁:Synchronized、重入锁、读写锁 一文中,我们了解了synch和读写锁,我们发现使用锁的时候一次只允许一条线程方法。那么有什么东西可以提供更强大的控制方法么?这个东西就是信号量。

信号量提供的主要方法:

1
2
3
4
5
6
7
8
9
10
11
12
//创建具有给定许可数的信号量
Semaphore(int permits):构造方法,创建
//拿走1个许可
void acquire()
//拿走多个许可
void acquire(int n)
//释放一个许可
void release()
//释放n个许可
void release(int n):
//当前可用的许可数
int availablePermits():

下面来看使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class SemaphoreThreadDemo {
    public static Semaphore semaphore = new Semaphore(5);

    static class ThreadDemo extends Thread {
        @Override
        public void run() {
            try {
                semaphore.acquire();
                System.out.println(Thread.currentThread().getId() + "号线程在"+System.currentTimeMillis()+"获取资源");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                semaphore.release();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 30; i++) {
            new ThreadDemo().start();
        }
    }

}


LockSupport

我们在 Hello,Thread 和 生产者消费者模型 两篇文章中使用过wait和notify实现了线程之间的协作,其实关于线程协作JDK还为我们提供了另外一个工具类LockSupport。

使用LockSupport实现等待通知功能时还不需要获取锁哦

先来看一下LockSupport的常用方法:

1
2
3
4
// 禁用当前线程
static void park()
// 如果参数线程的不可用,则使其可用。
static void unpark(Thread thread)

来看一下示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class LockSupportThreadDemo {
    public static Thread thread;
    static class WaitThreadDemo extends Thread {
        @Override
        public void run() {
            System.out.println("WaitThread wait,time=" + System.currentTimeMillis());
            thread = Thread.currentThread();
            LockSupport.park();
            System.out.println("WaitThread end,time=" + System.currentTimeMillis());
        }
    }
    static class NotifyThreadDemo extends Thread {
        @Override
        public void run() {
            System.out.println("NotifyThread notify,time=" + System.currentTimeMillis());
            LockSupport.unpark(thread);
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("NotifyThread end,time=" + System.currentTimeMillis());
        }
    }
    public static void main(String[] args) {
        WaitThreadDemo waitThreadDemo = new WaitThreadDemo();
        NotifyThreadDemo notifyThreadDemo = new NotifyThreadDemo();
        waitThreadDemo.start();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        notifyThreadDemo.start();
    }
}

 

博客所有文章首发于公众号《Java学习录》转载请保留
扫码关注公众号即可领取2000GJava学习资源

 

多线程工具类:CountDownLatch、CyclicBarrier、Semaphore、LockSupport

  •