iT邦幫忙

0

day15 了解執行緒(Multithreading)與競爭條件(Race Condition) 的概念

  • 分享至 

  • xImage
  •  

Race Condition(競爭條件):
當多個執行緒(Threads)同時存取或修改同一個共享資源,
因為「執行順序不確定」,導致程式結果不可預期的問題。
多執行緒同時存取共享資源,結果不穩定。
常見錯誤:數值錯誤、資料遺失、程式崩潰
解決方法:同步(synchronized)、鎖(Lock)、原子操作(Atomic)。
synchronized:同一時間只允許一個執行緒進入方法或區塊。
AtomicInteged:提供原子操作,適合計數或累加,效能比 synchronized 高。

AtomicInteger 保證單一變數操作原子,但若你需要在一次操作中讀多個變數並做判斷與更新(複雜邏輯),可能還是需要 synchronized 或其他鎖來保證一致性。
AtomicInteger 的方法本身是 thread-safe 的,你不用再加鎖來保護它的 incrementAndGet() 等方法。

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

public class Day15Demo {
public static void main(String[] args) {
String host = "127.0.0.1";
int start=20,end=80;
int timeout=500;
int threads=20;

    AtomicInteger openCount = new AtomicInteger(0);
    ExecutorService ex = Executors.newFixedThreadPool(threads);

    for (int p = start; p <=end; p++) {
        final int port = p;
        ex.submit(()->{
            try(Socket socket = new Socket();){
                socket.connect(new InetSocketAddress(host,port),timeout);
                System.out.printf("Port %d -> OPEN%n", port);
                openCount.incrementAndGet();//原子遞增
            }catch (IOException e){
                System.out.printf("Port %d -> CLOSED/TIMEOUT%n", port);
            }

        });
    }
    ex.shutdown();
    try {
        boolean finished = ex.awaitTermination(5, TimeUnit.MINUTES);
        if (!finished) {
            System.out.println("Timeout: tasks did not finish within 5 minutes. Attempting forced shutdown...");
            ex.shutdownNow();
            ex.awaitTermination(30, TimeUnit.SECONDS);
        }
    }catch (InterruptedException ie){
        Thread.currentThread().interrupt();
        ex.shutdownNow();
}
    System.out.println("Open ports count = " + openCount.get());
}

}

打完程式從程式碼學到了
import java.util.concurrent.*;
java.util.concurrent 是 Java 裡的「並行 / 多執行緒工具包」
匯入 * → 代表這個 package 裡的所有類別都可以用
常用的類別:
ExecutorService:管理多個執行緒、提交任務
Executors:快速建立 Thread Pool
TimeUnit:設定時間單位(秒、毫秒…)
Future / Callable:異步任務回傳結果

import java.util.concurrent.atomic.AtomicInteger;
AtomicInteger:提供原子操作整數
讓多執行緒同時操作同一個整數也安全,不會發生 race condition
常用方法:
incrementAndGet() → +1 並回傳新值
get() → 讀取目前值

java.util.concurrent → 「同時跑多個掃描任務」
AtomicInteger → 「安全計算已開啟的 port 數量」
一起使用就能讓 Port Scanner 快速且安全地在多執行緒環境下運作。

ex.submit(() -> { ... }):
提交一個 Runnable(lambda)給執行緒池。submit 會把任務放到工作隊列,當有空閒執行緒就會執行它。

ex.shutdown();
不再接受新任務,但會讓已提交的任務繼續執行直至完成或被取消。

多執行緒環境下的輸出問題:
多個 thread 同時呼叫 System.out.printf,可能導致輸出交錯或順序亂掉(interleaving),之後有時間再來學習怎麼讓結果有序排列。

今天我深入理解了「多執行緒程式設計」的核心基本概念,不只是把工作分給多個 thread 去做,而是要同時考慮安全性、效率。也讓我體會到「先設計安全可靠的程式,再追求效率」的重要性。
多執行緒雖然能加快任務,但如果忽略 race condition、例外處理或資源關閉,反而容易出 bug。
透過 AtomicInteger、try-with-resources、ExecutorService,我學會用現代 Java 的工具安全又優雅地完成任務。
也學會用固定執行緒池來控制同時運作的 thread 數量,避免直接用太多 Thread 導致系統資源耗盡。
透過 submit 提交任務、shutdown 停止接收新任務、awaitTermination 等待任務完成,我對「如何安全地結束多執行緒任務」有了基礎概念。


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

尚未有邦友留言

立即登入留言