iT邦幫忙

0

day16 多執行緒掃描結果的有序排列

  • 分享至 

  • xImage
  •  

昨天練習的輸出結果是沒有序的,因為Java 的多執行緒是非同步(asynchronous)的。每個 Thread 自己跑,主程式不等它。
不同的執行緒完成時間不同(例如連線 timeout、I/O 等因素),
System.out.printf() 是共享資源(多執行緒同時寫),就會交錯。
如果想解決這個方法可以「照 port 由小到大」輸出,
然後用 Future + List 這種結構來「收集結果」。

Future 就像「未來的包裹 」。
你先寄出任務(submit())
Java 回你一個「未來結果的票根(Future)」
等任務真的完成後,你才能打開包裹(f.get())
最後由主執行緒自己印出。
若我們希望「照 port 由小到大」輸出,
可以用 Future + List 這種結構來「收集結果」,
最後由主執行緒自己印出。

package day1;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.;
import java.util.concurrent.
;
import java.util.concurrent.atomic.AtomicInteger;

public class Day16demo {
public static void main(String[] args) throws InterruptedException, IOException {
String host = "127.0.0.1";
int start = 20, end = 40;
int timeout = 500;
int threads = 20;

    ExecutorService ex = Executors.newFixedThreadPool(threads);
    List<Future<String>>results=new ArrayList<>();
    AtomicInteger count = new AtomicInteger(0);

    for(int p=start ; p<=end ; p++){
      final int port=p;
      Future<String>future=ex.submit(() -> {
          try(Socket socket=new Socket()){
              socket.connect(new InetSocketAddress(host,port),timeout);
              count.incrementAndGet();
              return String.format("Port %d ->OPEN ", port);
          }catch (IOException e) {
              return String.format("Port %d -> CLOSED/TIMEOUT", port);
          }
      }); results.add(future);
    }
    ex.shutdown();
    ex.awaitTermination(5,TimeUnit.MINUTES);

    List<String> Output=new ArrayList<>();
    for(Future<String> f:results){
        try{
            Output.add(f.get());
        }catch (ExecutionException e){
            Output.add("執行錯誤"+e.getMessage());
        }
    }
    for(String line:Output){
        System.out.println(line);
    }
    System.out.println("Open ports count = " + count.get());
}

}

Future 一個「未來的結果」容器,等 thread 結束後可以 .get() 拿到字串結果。

ex.submit(() -> {...}) 提交一個任務(Lambda 寫法的 Runnable / Callable)。

results.add(future) 把每個任務的結果記下來。
f.get() 等任務執行完,取得結果字串。
有序輸出因為是照 for (p=start; p<=end) 提交的,所以取出時自然是有序的。

因為是用 for (Future f : results) 依照提交的順序讀取。
而且 .get() 會等每個任務完成才拿結果。
所以即使多執行緒是亂跑的,最後印出來會依照 results 的順序整理好。

https://ithelp.ithome.com.tw/upload/images/20251009/20179429GY44JEwybl.png

練習這段程式碼今天學到了
多執行緒輸出會亂序,因為同時執行、沒有固定順序。
Future 可以讓每個執行緒回傳結果,等全部做完再依序取出。
ExecutorService 是用來管理執行緒的工具。
AtomicInteger 可確保多執行緒同時加減數字時不會錯。
awaitTermination() 可以讓主程式等執行緒全部跑完再繼續。
整個重點:讓多執行緒的結果「有序」輸出。

今天學習的「有序輸出」讓我更理解多執行緒的本質。
以前我只知道開很多 thread 會比較快,但沒想到會導致結果亂掉。
今天用 Future 把結果存起來再統一印出,就能保證順序正確,這讓我覺得程式的邏輯清楚很多。
雖然我還不太熟 Future、ExecutorService 這些東西,但我慢慢理解這是控制「多個任務」的關鍵。
從這個練習我也學到,程式不只是「能跑」而已,還要讓結果整齊、有邏輯。


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言