java多線程 —— 兩種實際應用情境類比

來源:互聯網
上載者:User

標籤:

java多線程-兩種實際應用情境類比 轉自 薛定諤的貓

(一)

先說說第一個,類比對資訊的發送和接收。情境是這樣的:

就像筆者之前做的訊息的發送,一個是伺服器,一個是用戶端。發送的話,要保證資訊100%的發送給用戶端,那麼發給用戶端之後,用戶端返回一個訊息告訴伺服器,已經收到。當伺服器一直沒有收到用戶端返回的訊息,那麼伺服器會一直發送這個資訊,直到用戶端發送回確認資訊,這時候再重複資料刪除發送的這個資訊。

為了類比這個情境,這裡寫兩個線程,一個是發送,一個是接收,把發送的資訊,要儲存到安全執行緒的對象裡面,防止發生安全執行緒問題,這裡採用concurrenthashmap。

發送代碼:

 

package com.TestThread;/* *  * @author 薛定餓的貓 *  * */import java.util.Map.Entry;import java.util.concurrent.ConcurrentHashMap;public class PushThread extends Thread {    @Override    public void run() {        // TODO Auto-generated method stub        try {            sleep(6000);            while(MainThread.pushmessage.size()>0){                //重發訊息                for(Entry<Integer, String> hashMap:MainThread.pushmessage.entrySet()){                    System.out.println("訊息id:"+hashMap.getKey()+"未發送成功,在此重發:"+hashMap.getValue());                }                sleep(1000);            }        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }    }

發送代碼,是不斷遍曆記憶體對象councurrenthashmap,從中取出資訊,不斷的重發。其中MainThread.pushmessage是記憶體對象,在最後一段代碼中有定義。

當確認接收到資訊後,另外一個線程來刪除記憶體對象。

刪除的代碼:

package com.TestThread;/* *  * @author 薛定餓的貓 *  * */import java.util.Map.Entry;public class RemoveThread extends Thread {    @Override    public void run() {        // TODO Auto-generated method stub        try {            for (int i = 0; i < 10000; i++) {                sleep(2000);                for(Entry<Integer, String> map:MainThread.pushmessage.entrySet()){                    if (map.getKey()==i) {                        System.out.println("成功收到id為:"+map.getKey()+"返回的資訊,刪除該元素");                        MainThread.pushmessage.remove(map.getKey());                    }                }                System.out.println("記憶體對象中的元素數量為:"+MainThread.pushmessage.size());            }        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }    }

這裡是來刪除已收到的資訊,然後從記憶體中刪除,不再發送。

然後寫一個主類入口:

package com.TestThread;/* *  * @author 薛定餓的貓 *  * */import java.util.concurrent.ConcurrentHashMap;public class MainThread {    public static ConcurrentHashMap<Integer, String> pushmessage=new ConcurrentHashMap<Integer,String>();    public static void main(String[] args) {        for (int i = 0; i < 10; i++) {            pushmessage.put(i, "該訊息是id為"+i+"的訊息");        }        Thread pushThread=new PushThread();        Thread remove=new RemoveThread();        pushThread.start();        remove.start();        for (int i = 10; i < 20; i++) {            pushmessage.put(i, "又一波到來,訊息是id為"+i+"的訊息");        }    }}

這樣兩個線程可以輪流的進行各自的事情,並且不會造成資料安全的問題。用這種方式,再結合Androidpn的推送機制,會更加符合實際生產中的應用。

(二)多線程同步計數器

多線程同步計數器,按道理也是可以按照上面的方式來進行處理,定義一個像concurrenthashmap的變數。在java中,確實也有另外一種變數,原子變數Atomic,有AtomicLong,AtomicInteger,AtomicReference這些。

如果在多線程環境下要給一些值賦唯一id的話,這個時候,就要考慮這個id的安全性問題,也就是一致性的問題,不能重複。這裡有兩個實現的代碼:

package com.test;public class ThreadCount {    public static void main(String[] args) {                Thread[] threads=new Thread[10000];        for (int i = 0; i < 10000; i++) {            threads[i]=new AThread();            threads[i].start();        }    }}class AThread extends Thread{    @Override    public void run() {        // TODO Auto-generated method stub        @SuppressWarnings("unused")        Counter counter=new Counter();        System.out.println(Counter.calNum());    }    }class Counter{     private static long num;     public Counter(){         synchronized (Counter.class) {            num++;        }     }     public static synchronized long calNum(){         return num;     }}

這裡建立了10000個線程,每個線程都來訪問這個計數器,在構造方法中來進行值的遞增。

在計數器中,有兩次用到同步,很多人都說用同步,經常會對效能造成影響。於是,用第二種的原子變數,這個效能應該會更好。

代碼:

package com.test;import java.util.concurrent.atomic.AtomicLong;public class ThreadCount {    public static void main(String[] args) {                Thread[] threads=new Thread[10000];        for (int i = 0; i < 10000; i++) {            threads[i]=new AThread();            threads[i].start();        }    }}class AThread extends Thread{    @Override    public void run() {        System.out.println(MyCounter.calNum());    }    }class Counter{     private static long num;     public Counter(){         synchronized (Counter.class) {            num++;        }     }     public static synchronized long calNum(){         return num;     }}class MyCounter{    private static AtomicLong num=new AtomicLong();        public static synchronized long calNum(){        return num.incrementAndGet();    }}


這樣寫的話,在調用這個計數器的時候,直接不需要再new一個MyCounter對象。

這樣可以作為工具類,直接調用MyCounter的calNum方法。

java多線程 —— 兩種實際應用情境類比

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.