簡體   English   中英

對Java在多處理期間如何共享變量感到困惑

[英]Confused on how Java shares variables during multiprocessing

我剛剛開始使用Java,因此很抱歉,如果這個問題的答案很明顯。 我真的不知道如何在Java中共享變量。 我一直在玩python,想嘗試將一些代碼移植到Java上以更好地學習語言。 我的代碼很多,但是我不確定在Java中變量的多處理和共享是如何工作的(我的進程沒有磁盤綁定,並且使用很多cpu和列表搜索)。

在Python中,我可以這樣做:

from multiprocessing import Pool, Manager
manager = Manager()
shared_list = manager.list()
pool = Pool(process=4) 
for variables_to_send in list_of_data_to_process:
       pool.apply_async(function_or_class, (variables_to_send, shared_list))
pool.close()
pool.join()

我在弄清楚如何在Java中像這樣進行多處理和共享時遇到了一些麻煩。 這個問題幫助我(通過代碼)了解了如何實現runnable可以提供幫助,並且我開始認為Java可能會自動對多線程進行處理(如果我錯了,請更正我,我讀到一旦線程超出了CPU的容量,它們被轉移到另一個CPU?甲骨文文檔似乎更關注線程而不是多處理)。 但這並未說明如何在過程之間共享列表或其他變量(並使它們保持足夠接近的同步)。

有什么建議或資源嗎? 我希望我正在尋找錯誤的東西(java多處理),並且希望它與我上面的代碼一樣簡單(或類似簡單)。

謝謝!

線程和進程之間有一個重要的區別,您現在正在運行它:除了某些例外, 線程共享內存,而進程不共享內存

請注意,真正的操作系統幾乎可以滿足我要說的一切,但是在典型情況下並沒有使用這些功能。 因此,要啟動一個新進程,必須使用系統調用(在* nix上,這是fork() )以某種方式克隆當前進程,然后替換其中的代碼,堆棧,命令行參數等。子進程與另一個系統調用(在* nix上,這是exec()系列系統調用)。 Windows具有這兩個系統調用的大致等效項,因此我要說的都是跨平台的。 而且,Java運行時環境在幕后負責所有這些系統調用,沒有JNI或其他互操作技術,您將無法真正執行它們。

關於此模型,有兩點需要注意:子進程不共享父進程的地址空間,並且子進程的整個地址空間在exec()調用中被替換。 因此,父進程中的變量對子進程不可用,反之亦然。

線程模型完全不同。 線程有點像精簡進程,因為每個線程都有自己的指令指針,並且(在大多數系統上)線程是由操作系統調度程序調度的。 但是,線程是進程的一部分。 每個進程至少有一個線程,並且進程中的所有線程共享內存。

現在解決您的問題:

如代碼示例所示,Python的多處理模塊只需很少的努力即可生成進程。 在Java中,產生一個新進程需要更多的工作。 它涉及使用ProcessBuilder.start()Runtime.exec()創建一個新的Process對象。 然后,您可以將字符串傳遞給子進程,獲取其輸出,等待其退出,以及其他一些通信原語。 我建議編寫一個程序來充當協調器並啟動每個子進程,並編寫一個與您的示例中的function_or_class大致對應的工作程序。 協調器可以打開工作程序的多個副本,為每個任務分配一個任務,然后等待所有工作程序完成。

您可以為此目的使用Java線程。 您需要創建一個用戶定義的類。 該類應該具有setter方法,通過該方法可以設置shared_list對象。 在Run()方法中實現Runnable接口並執行處理任務。 您可以在互聯網上找到很好的例子。 如果共享相同的shared_list實例,則需要確保對該變量的訪問已同步。

這不是在Java中使用線程的最簡單方法,但是對您發布的python代碼不開放。 任務類是可調用接口的實例,並且具有調用方法。 當我們創建10000個Task實例中的每個實例時,我們將它們傳遞給同一列表的引用。 因此,當所有這些對象的調用方法都被調用時,它們將使用相同的列表。

我們在這里使用4個線程的固定大小的線程池,因此我們提交的所有任務都將排隊,並等待一個線程可用。

public class SharedListRunner {
    public void RunList() {
        ExecutorService executerService = Executors.newFixedThreadPool(4);
        List<String> sharedList = new List<String>();
        sharedList.add("Hello");
        for(int i=0; i < 10000; i++)
            executerService.submit(new Task(list));
    }
}

public class Task implements Callable<String> {

    List<String> sharedList;    

    public Task(List<String> sharedList) {
            this.sharedList = sharedList;
    }

    @Override
    public String call() throws Exception {
            //Do something to shared list
            sharedList.size();  
            return "World";
    }
}

任何時候都有4個線程正在訪問該列表。 如果要進一步挖掘訪問該列表的4個Java線程,則可能有更少的OS線程為這4個Java線程提供服務,並且甚至更少的處理器線程通常每個cpu內核為2或4。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM