文章出處

場景

開發中遇到一個場景,業務操作會不定時的產生工作任務,這些工作任務需要放入到一個隊列中,而另外會有一個線程一直檢測這個隊列,隊列中有任務就從隊列中取出并進行運算。

問題

業務場景倒是簡單,只不過這里會有一個問題,就是如果隊列中沒有數據那么線程就會一直掃描,這樣就會浪費資源。

解決方法

在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.


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 AutoPoster 的頭像
    AutoPoster

    互聯網 - 大數據

    AutoPoster 發表在 痞客邦 留言(0) 人氣()