文章出處
文章列表
場景
開發中遇到一個場景,業務操作會不定時的產生工作任務,這些工作任務需要放入到一個隊列中,而另外會有一個線程一直檢測這個隊列,隊列中有任務就從隊列中取出并進行運算。
問題
業務場景倒是簡單,只不過這里會有一個問題,就是如果隊列中沒有數據那么線程就會一直掃描,這樣就會浪費資源。
解決方法
在windows中有一個事件對象可以用于線程的控制,Event有兩種狀態:有信號和無信號,通過這個信號來做一個開關,可以達到線程的開關。在.net中有個AutoResetEvent類是實現這套方法的,但在java中我沒有找到類似的實現,但是java并發包中有個Semaphore,那就通過這個Semaphore來完成吧。
怎么做
Semaphore可以設置信號量的數量,每一個信號量稱為一個許可證,需要進行同步的線程向這個信號量對象獲取許可證,獲得成功則線程繼續執行,如果沒有許可證則會阻塞。我們這個場景下只要將信號量設置為1個許可證,然后通過控制這個許可證即可實現Event的效果。
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Semaphore; public class ThreadRunable { private static ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<String>(); private static Semaphore semp = new Semaphore(1); public static void main(String[] args) throws InterruptedException { semp.acquire();//先占用信號量 Thread newThread = new Thread(new Worker()); newThread.start(); try { Thread.sleep(1000); queue.add("第1條數據"); semp.release();//放入數據放釋放信號量,使得線程可以運行 System.out.println("可用許可證:" + semp.availablePermits()); } catch (InterruptedException e) { e.printStackTrace(); } try { Thread.sleep(5000); queue.add("第2條數據"); semp.release();//放入數據放釋放信號量,使得線程可以運行 System.out.println("可用許可證:" + semp.availablePermits()); } catch (InterruptedException e) { e.printStackTrace(); } } static class Worker implements Runnable { @Override public void run() { while (true) { try { semp.acquire();//獲取許可證,如果沒有可用許可證則阻塞 //業務代碼,從隊列中讀數據做一些想干的事情 while (queue.isEmpty() == false) { String value = queue.poll(); if (value != null && value != "") { System.out.println("value: " + value); } } System.out.println("it's down."); } catch (Exception e) { } } } } }
在段代碼就是一個簡單的模擬,實現的過程如下:
1、全局初始化信號量對象,設置一個許可證
2、首先占用許可證,使得線程在獲取許可證時就會阻塞
3、然后模擬一些添加隊列的數據,在添加隊列的時候同時釋放許可證,這樣就可以喚醒線程了
4、線程喚醒后去讀取隊列并做一些操作,完成后又去嘗試獲取許可證
5、如果沒有許可證則阻塞,直到下次有數據添加隊列時再次釋放許可證時再次喚醒線程
最后運行的結果:
可用許可證:1
value: 第1條數據
it's down.
可用許可證:1
value: 第2條數據
it's down.
文章列表
全站熱搜