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

CountDownLatch

假如有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以。

比如你想要买套房子,但是呢你现在手上没有钱。你得等这个月工资发了、然后年终奖发了、然后朋友借你得钱还给你了、然后再给朋友借一部分才可以买,这种场景你就可以使用CountDownLatch。

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

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

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

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

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可以完成前者的全部功能,但是相比前者,它的功能更加的强大。

  1. CyclicBarrier翻译过来的中文名称叫循环栅栏,顾名思义它可以循环使用

  2. CyclicBarrier还可以接收一个Runnable对象,当栅栏循环一次技术后会执行一次Runnable

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

//构造方法,第一个参数为栅栏饿长度,第二个就是上方所说的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的基本使用示例代码:

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对象,然后在瞬间释放所有任务的锁。

14完成任务	
15完成任务	
16完成任务	
17完成任务	
18完成任务	
所有任务已经完成之后单独执行的任务!	
到达屏障点每个线程都会瞬时继续执行	
到达屏障点每个线程都会瞬时继续执行	
到达屏障点每个线程都会瞬时继续执行	
到达屏障点每个线程都会瞬时继续执行	
到达屏障点每个线程都会瞬时继续执行	
19完成任务	
20完成任务	
21完成任务	
22完成任务	
23完成任务	
所有任务已经完成之后单独执行的任务!	
到达屏障点每个线程都会瞬时继续执行	
到达屏障点每个线程都会瞬时继续执行	
到达屏障点每个线程都会瞬时继续执行	
到达屏障点每个线程都会瞬时继续执行	
到达屏障点每个线程都会瞬时继续执行

Semaphore

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

信号量提供的主要方法:

//创建具有给定许可数的信号量	
Semaphore(int permits):构造方法,创建	
//拿走1个许可	
void acquire()	
//拿走多个许可	
void acquire(int n)	
//释放一个许可	
void release()	
//释放n个许可	
void release(int n):	
//当前可用的许可数	
int availablePermits():

下面来看使用示例:

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的常用方法:

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

来看一下示例代码:

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();	
    }	
}

640?wx_fmt=gif

640?wx_fmt=jpeg

 收藏转发好看再走呗!

640?wx_fmt=gif
 

点击下方“阅读原文”查看源码!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值