Java線程操作-模擬本地多線程搶紅包

沒有寫過搶紅包的處理程序,考慮到多線程是核心,所以練習先寫一個本地使用多線程來搶紅包的模擬程序。程序運行要達到的效果,是最終紅包都被搶完,並對數據進行統計,統計結果和總庫存要完全吻合。

沒有過多的解釋,直接就一個測試類。

package com.chris.java;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by Chris Chan
 * 2020/2/11 19:27
 * Use for:
 * Explain: 線程測試
 */
public class TestThread {
    private static volatile int amount = 1143;//紅包總數
    private static Map<String, Integer> map = new HashMap<>(16);//記錄每個線程搶到的紅包
    private static Object boxLock = new Object();//線程鎖 可以假設是裝紅包的盒子

    public static void main(String[] args) {
        action();
    }

    //搶紅包
    private static void action() {
        Runnable runnable = () -> {
            String threadName = Thread.currentThread().getName();
            while (amount > 0) {
                //搶一次 獨佔這把鎖 加鎖部分的操作應該越少越好,減少時間消耗,可以提升性能
                synchronized (boxLock) {
                    /*
                    可以想象,在最後的一個紅包被搶前,有一大堆人(線程)在後面排隊獲取這把鎖,
                    如果讓這些已經進入循環的線程繼續,則後面這些線程可能會繼續搶一些
                    不存在的紅包,使紅包庫存編程負數。所以需要在這裏檢查一下盒子裏面
                    是否空空如也。
                     */
                    if (amount <= 0) {
                        break;
                    }
                    amount--;//減庫存 如果不想打印控制檯信息,就用這一行替換下面一行
                    //減庫存放在這一行中,是爲了避免兩次控制檯輸出造成過多的時間消耗
                    //System.out.println("紅包庫存 " + (amount--) + "個 線程 " + threadName + " 搶到一個紅包 還剩 " + amount + " 個");
                    //下面這一行代碼只是爲了便於檢查,其實不必要,會增加時間消耗
//                    if (amount % 5 == 0) {
//                        System.out.println();
//                    }
                }

                Integer total = map.get(threadName);
                if (null == total) {
                    map.put(threadName, 1);
                } else {
                    map.put(threadName, total + 1);
                }
            }
        };

        Thread thread01 = new Thread(runnable);
        Thread thread02 = new Thread(runnable);
        Thread thread03 = new Thread(runnable);

        thread01.start();
        thread02.start();
        thread03.start();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("\n彙總:\n紅包還剩 " + amount + " 個");
        map.keySet().stream().forEach(key -> System.out.println("\t" + key + " : " + map.get(key)));
        System.out.println("紅包一共被領取 " + map.values().stream().reduce(0, (v1, v2) -> v1 + v2) + "  個");
    }

}

開始時遇到一些問題,就是變-1,後來添加來加鎖後檢查的邏輯才解決。一般這種問題都是解決問題的思路需要調整,生活中如何解決問題,程序中就如何實現邏輯。解決了前者,後者也就不是什麼問題。另外加鎖後的操作應該儘可能少消耗時間,否則可能造成時間片消費的不均衡。

運行結果:

換過幾次參數都沒有什麼問題,不過這只是本地測試,邏輯要簡單很多。下次寫一個全套的前後端測試程序,需要用好http請求,紅包數據要放在數據庫。

發佈了106 篇原創文章 · 獲贊 46 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章