java.util 常见_Java基础知识-java.util.concurrent包下常见类的使用
一,Condition
一個(gè)場(chǎng)景,兩個(gè)線程數(shù)數(shù),同時(shí)啟動(dòng)兩個(gè)線程,線程A數(shù)1、2、3,然后線程B數(shù)4、5、6,最后線程A數(shù)7、8、9,程序結(jié)束,這涉及到線程之間的通信。
public classConditionTest {static classNumberWrapper {public int value = 1;
}public static voidmain(String[] args) {//初始化可重入鎖
final Lock lock = newReentrantLock();//第一個(gè)條件當(dāng)屏幕上輸出到3
final Condition reachThreeCondition =lock.newCondition();//第二個(gè)條件當(dāng)屏幕上輸出到6
final Condition reachSixCondition =lock.newCondition();//NumberWrapper只是為了封裝一個(gè)數(shù)字,一邊可以將數(shù)字對(duì)象共享,并可以設(shè)置為final//注意這里不要用Integer, Integer 是不可變對(duì)象
final NumberWrapper num = newNumberWrapper();//初始化A線程
Thread threadA = new Thread(newRunnable() {
@Overridepublic voidrun() {//需要先獲得鎖
lock.lock();
System.out.println("ThreadA獲得lock");try{
System.out.println("threadA start write");//A線程先輸出前3個(gè)數(shù)
while (num.value <= 3) {
System.out.println(num.value);
num.value++;
}//輸出到3時(shí)要signal,告訴B線程可以開(kāi)始了
reachThreeCondition.signal();
}finally{
lock.unlock();
System.out.println("ThreadA釋放lock");
}
lock.lock();try{//等待輸出6的條件
System.out.println("ThreadA獲得lock");
reachSixCondition.await();
System.out.println("threadA start write");//輸出剩余數(shù)字
while (num.value <= 9) {
System.out.println(num.value);
num.value++;
}
}catch(InterruptedException e) {
e.printStackTrace();
}finally{
lock.unlock();
System.out.println("ThreadA釋放lock");
}
}
});
Thread threadB= new Thread(newRunnable() {
@Overridepublic voidrun() {try{
lock.lock();
System.out.println("ThreadB獲得lock");
Thread.sleep(5000);//是await方法釋放了鎖
while (num.value <= 3) {//等待3輸出完畢的信號(hào)
reachThreeCondition.await();
}
}catch(InterruptedException e) {
e.printStackTrace();
}finally{
lock.unlock();
System.out.println("ThreadB釋放lock");
}try{
lock.lock();
System.out.println("ThreadB獲得lock");//已經(jīng)收到信號(hào),開(kāi)始輸出4,5,6
System.out.println("threadB start write");while (num.value <= 6) {
System.out.println(num.value);
num.value++;
}//4,5,6輸出完畢,告訴A線程6輸出完了
reachSixCondition.signal();
}finally{
lock.unlock();
System.out.println("ThreadB釋放lock");
}
}
});//啟動(dòng)兩個(gè)線程
threadB.start();
threadA.start();
}
}
創(chuàng)建方式:通過(guò)Lock創(chuàng)建,Lock.newCondition();
常用方法:
await():阻塞,直到相同的Condition調(diào)用了signal方法。
signal():通知。
總結(jié):Condition必須與Lock一起使用(wait()、notify()必須與synchronized一起使用,否則運(yùn)行會(huì)報(bào)錯(cuò)java.lang.IllegalMonitorStateException),相比于wait與notify更加的靈活,可以設(shè)置各種情形,如上例中的到達(dá)3和到達(dá)6兩個(gè)條件。
二,CountDownLatch
直接上代碼:
public classCountDownLatchTest {public static voidmain(String[] args) {final CountDownLatch c = new CountDownLatch(3);//總數(shù)3
Thread t1 = new Thread(newRunnable(){
@Overridepublic voidrun() {try{
System.out.println("開(kāi)始等");
c.await();//阻塞,等待countDown,當(dāng)countDown到0就執(zhí)行后面的完事了
System.out.println("完事");
}catch(InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t2= new Thread(newRunnable(){
@Overridepublic voidrun() {for(int i=3;i>0;i--){
c.countDown();//減1
}
}
});
t1.start();
t2.start();
}
}
創(chuàng)建方式:直接創(chuàng)建,new CountDownLatch(int num);
常用方法:
await():阻塞,直到countDown方法被執(zhí)行了num次。
countDown():減
總結(jié):適用于一個(gè)線程等待其他線程的情景。
三,CyclicBarrier
通過(guò)代碼思考一下與CountDownLatch的區(qū)別。
public classMainMission {privateCyclicBarrier barrier;private final static int threadCounts = 5;public voidrunMission() {
ExecutorService exec=Executors.newFixedThreadPool(threadCounts);//new 的時(shí)候要傳入數(shù)字,我發(fā)現(xiàn),這個(gè)類似semaphore,如果位置不足,線程會(huì)搶位置。數(shù)字要是threadCounts+1為主線程留一個(gè)位子,但實(shí)際測(cè)試中發(fā)現(xiàn),只要等于threadCount就可以
barrier=new CyclicBarrier(threadCounts+1);for(int i=0;i<5;i++){
exec.execute(newMission(barrier));
}try{
barrier.await();
}catch(InterruptedException e) {
e.printStackTrace();
}catch(BrokenBarrierException e) {
e.printStackTrace();
}try{
Thread.sleep(1);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("所有任務(wù)都執(zhí)行完了");
exec.shutdown();//如果不關(guān)閉,程序一直處于運(yùn)行狀態(tài)
}public static voidmain(String[] args) {
MainMission m= newMainMission();
m.runMission();
}
}class Mission implementsRunnable{privateCyclicBarrier barrier;publicMission(CyclicBarrier barrier){this.barrier =barrier;
}
@Overridepublic voidrun() {
System.out.println(Thread.currentThread().getName()+"開(kāi)始執(zhí)行任務(wù)");try{int sleepSecond = new Random().nextInt(10)*1000;
System.out.println(Thread.currentThread().getName()+"要執(zhí)行"+sleepSecond+"秒任務(wù)");
Thread.sleep(sleepSecond);
}catch(InterruptedException e) {
e.printStackTrace();
}try{
barrier.await();
}catch(InterruptedException e) {
e.printStackTrace();
}catch(BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"執(zhí)行完畢");
}
}
創(chuàng)建方式:直接創(chuàng)建,new?CyclicBarrier(int num);
常用方法:
await():阻塞,直到阻塞的線程數(shù)量達(dá)到num個(gè)。
總結(jié):想想一下百米跑,所有運(yùn)動(dòng)員都就位之后才會(huì)發(fā)令起跑,線程調(diào)用await意味著說(shuō),我準(zhǔn)備好了。
四,Semaphore
下面是一個(gè)上廁所的例子,廁所位置有限,想用得排隊(duì)了。實(shí)現(xiàn)使用的就是信號(hào)量,可以看出信號(hào)量可以用來(lái)做限流。
public class MySemaphore implementsRunnable{
Semaphore position;private intid;public MySemaphore(inti,Semaphore s){this.id=i;this.position=s;
}
@Overridepublic voidrun() {try{if(position.availablePermits()>0){
System.out.println("顧客["+this.id+"]進(jìn)入廁所,有空位");
}else{
System.out.println("顧客["+this.id+"]進(jìn)入廁所,沒(méi)空位,排隊(duì)");
}
position.acquire();//只有在acquire之后才能真正的獲得了position
System.out.println("#########顧客["+this.id+"]獲得坑位");
Thread.sleep((int)(Math.random()*100000));
System.out.println("@@@@@@@@@顧客["+this.id+"]使用完畢");
position.release();
}catch(Exception e){
e.printStackTrace();
}
}public static voidmain(String args[]){
ExecutorService list=Executors.newCachedThreadPool();
Semaphore position=new Semaphore(2);for(int i=0;i<10;i++){
list.submit(new MySemaphore(i+1,position));
}
list.shutdown();
position.acquireUninterruptibly(2);
System.out.println("使用完畢,需要清掃了");
position.release(2);
}
}
創(chuàng)建方式:直接創(chuàng)建,new Semaphore(int num);
常用方法:
availablePermits():看現(xiàn)在可用的信號(hào)量。
acquire():嘗試獲取一個(gè)位置,如果獲取不到則阻塞。
release():釋放位置。
acquireUninterruptibly(int num):嘗試獲取num個(gè)許可,如果沒(méi)有足夠的許可則阻塞,一直阻塞到有足夠的許可釋放出來(lái)。調(diào)用這個(gè)方法的線程具有優(yōu)先獲取許可的權(quán)利。如果調(diào)用線程被interrupted,該線程并不會(huì)被打斷,它會(huì)繼續(xù)阻塞等待許可。
總結(jié):搶位置。
五,ReentrantLock
創(chuàng)建方式:
new ReentrantLock(); 此種創(chuàng)建方式會(huì)創(chuàng)建出一個(gè)非公平鎖。
new ReentrantLock(true); 此種方式會(huì)創(chuàng)建出一個(gè)公平鎖。
非公平鎖:當(dāng)鎖處于無(wú)線程占有的狀態(tài),此時(shí)其他線程和在隊(duì)列中等待的線程都可以搶占該鎖。
公平鎖:當(dāng)鎖處于無(wú)線程占有的狀態(tài),在其他線程搶占該鎖的時(shí)候,都需要先進(jìn)入隊(duì)列中等待。
tryLock()方法:嘗試去獲取鎖,如果沒(méi)有獲取到直接返回,不等待。
六,ReentrantReadWriteLock
創(chuàng)建方式:new ReentrantReadWriteLock();
常用方法:
readLock().lock();寫鎖
writeLock().lock();讀鎖
readLock().unlock();解鎖
writeLock().unlock();解鎖
總結(jié):
* 如果目前是讀鎖,其他讀鎖也可以進(jìn)請(qǐng)求,寫鎖不能進(jìn)。
* 如果目前是寫鎖,那么其他所有的鎖都不可以進(jìn)。
*適用于讀多寫少的情況,如果是寫多讀少用ReentrantLock。
七,Callable接口
*Callable接口支持返回執(zhí)行結(jié)果,此時(shí)需要調(diào)用FutureTask.get()方法實(shí)現(xiàn),此方法會(huì)阻塞主線程直到獲取結(jié)果;當(dāng)不調(diào)用此方法時(shí),主線程不會(huì)阻塞!
與Runnable對(duì)比:
1.Callable可以有返回值,Runnable沒(méi)有
2.Callable接口的call()方法允許拋出異常;而Runnable接口的run()方法的異常只能在內(nèi)部消化,不能繼續(xù)上拋;
八,線程池
提供的線程池有幾種:
//有數(shù)量限制的線程池
ExecutorService service=Executors.newFixedThreadPool(4);
//沒(méi)有數(shù)量限制的線程池
ExecutorService service=Executors.newCachedThreadPool();
//單線程池
ExecutorService service=Executors.newSingleThreadExecutor();
他們都是通過(guò)下面這個(gè)線程池實(shí)現(xiàn)的
有數(shù)量線程池的實(shí)現(xiàn)方式
public static ExecutorService newFixedThreadPool(intnThreads) {return newThreadPoolExecutor(nThreads/*核心線程數(shù)*/, nThreads/*最高線程數(shù)*/,0L/*高出核心線程數(shù)的線程最高存活時(shí)間*/, TimeUnit.MILLISECONDS/*高出核心線程數(shù)的線程最高存活時(shí)間單位*/,new LinkedBlockingQueue()/*任務(wù)隊(duì)列*/);
猜一猜剩下的兩種線程池是怎么實(shí)現(xiàn)的。如果想自己實(shí)現(xiàn),可以自己new
總結(jié)
以上是生活随笔為你收集整理的java.util 常见_Java基础知识-java.util.concurrent包下常见类的使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 诺基亚n73支持java_JAVA性能
- 下一篇: java toHalf_MoreThan