国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

批量任務(wù)體現(xiàn)多線(xiàn)程的威力!

dreamans / 808人閱讀

摘要:背景對(duì)于多線(xiàn)程的理解不是非常深刻,工作中用到多線(xiàn)程代碼的機(jī)會(huì)也不多,前不久遇到了一個(gè)使用場(chǎng)景,通過(guò)編碼實(shí)現(xiàn)后對(duì)于多線(xiàn)程的理解和應(yīng)用有了更加深刻的理解。多線(xiàn)程發(fā)送短信中的一個(gè)核心要點(diǎn)是,將全部手機(jī)號(hào)碼拆分成多個(gè)組后,分配給每個(gè)線(xiàn)程進(jìn)行執(zhí)行。

背景

對(duì)于多線(xiàn)程的理解不是非常深刻,工作中用到多線(xiàn)程代碼的機(jī)會(huì)也不多,前不久遇到了一個(gè)使用場(chǎng)景,通過(guò)編碼實(shí)現(xiàn)后對(duì)于多線(xiàn)程的理解和應(yīng)用有了更加深刻的理解。場(chǎng)景如下:現(xiàn)有給用戶(hù)發(fā)送產(chǎn)品調(diào)研的需求,運(yùn)營(yíng)的同事拿來(lái)了一個(gè)Excel文件,要求給Excel里面大約六萬(wàn)個(gè)手機(jī)號(hào)發(fā)送調(diào)研短信。

最簡(jiǎn)單的方法就是一個(gè)循環(huán)然后單線(xiàn)程順序發(fā)送,但是核心問(wèn)題在于,給短信運(yùn)營(yíng)商發(fā)短信的接口響應(yīng)時(shí)間較長(zhǎng),假設(shè)平均100ms的響應(yīng)時(shí)間,那么單線(xiàn)程發(fā)送的話(huà)需要6萬(wàn)*0.1秒=6000秒。顯然這個(gè)時(shí)間是不能接受的,運(yùn)營(yíng)商系統(tǒng)的發(fā)送接口我們是不能優(yōu)化的,只得增強(qiáng)自己的發(fā)送和處理能力才能盡快的完成任務(wù)。

批量發(fā)短信 讀取Excel中的信息 包依賴(lài)

工具類(lèi)代碼,Maven中引入如下兩個(gè)包


    org.apache.poi
    poi-ooxml
    3.17


    org.apache.xmlbeans
    xmlbeans
    2.6.0
讀取Excel的工具類(lèi)代碼
/**
 * 讀取Excel的文件信息
 *
 * @param fileName
 */
public static void readFromExcel(String fileName) {
    InputStream is = null;
    try {
        is = new FileInputStream(fileName);
        XSSFWorkbook workbook = new XSSFWorkbook(is);
        XSSFSheet sheet = workbook.getSheetAt(0);
        int num = 0;
        // 循環(huán)行Row
        for (int rowNum = 0, lastNum = sheet.getLastRowNum(); rowNum <= lastNum; rowNum++) {
            XSSFRow row = sheet.getRow(rowNum);
            String phoneNumber = getStringValueFromCell(row.getCell(0)).trim();
            phoneList.add(phoneNumber);
        }
        System.out.println(num);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
 
/**
 * 讀取Excel里面Cell內(nèi)容
 *
 * @param cell
 * @return
 */
private static String getStringValueFromCell(XSSFCell cell) {
 
    // 單元格內(nèi)的時(shí)間格式
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    // 單元格內(nèi)的數(shù)字類(lèi)型
    DecimalFormat decimalFormat = new DecimalFormat("#.#####");
    // 單元格默認(rèn)為空
    String cellValue = "";
 
    if (cell == null) {
        return cellValue;
    }
 
    // 按類(lèi)型讀取
    if (cell.getCellType() == XSSFCell.CELL_TYPE_STRING) {
        cellValue = cell.getStringCellValue();
    } else if (cell.getCellType() == XSSFCell.CELL_TYPE_NUMERIC) {
        // 日期轉(zhuǎn)為時(shí)間形式
        if (DateUtil.isCellDateFormatted(cell)) {
            double d = cell.getNumericCellValue();
            Date date = DateUtil.getJavaDate(d);
            cellValue = dateFormat.format(date);
        } else {
            // 其他轉(zhuǎn)為數(shù)字
            cellValue = decimalFormat.format((cell.getNumericCellValue()));
        }
    } else if (cell.getCellType() == XSSFCell.CELL_TYPE_BLANK) {
        cellValue = "";
    } else if (cell.getCellType() == XSSFCell.CELL_TYPE_BOOLEAN) {
        cellValue = String.valueOf(cell.getBooleanCellValue());
    } else if (cell.getCellType() == XSSFCell.CELL_TYPE_ERROR) {
        cellValue = "";
    } else if (cell.getCellType() == XSSFCell.CELL_TYPE_FORMULA) {
        cellValue = cell.getCellFormula().toString();
    }
    return cellValue;
}  
模擬運(yùn)營(yíng)商發(fā)送短信的方法
/**
 * 外部接口耗時(shí)長(zhǎng),通過(guò)多線(xiàn)程增強(qiáng)
 *
 * @param userPhone
 */
public void sendMsgToPhone(String userPhone) {
    try {
        Thread.sleep(SEND_COST_TIME);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("send message to : " + userPhone);
}
多線(xiàn)程發(fā)短信 簡(jiǎn)單的單線(xiàn)程發(fā)送
    /**
     * 單線(xiàn)程發(fā)送
     *
     * @param phoneList
     * @return
     */
    private long singleThread(List phoneList) {
        long start = System.currentTimeMillis();
        /*// 直接主線(xiàn)程執(zhí)行
        for (String phoneNumber : phoneList) {
            threadOperation.sendMsgToPhone(phoneNumber);
        }*/
        SendMsgExtendThread smet = threadOperation.new SendMsgExtendThread(phoneList);
        smet.start();
        long totalTime = System.currentTimeMillis() - start;
        System.out.println("單線(xiàn)程發(fā)送總時(shí)間:" + totalTime);
        return totalTime;
    }

對(duì)于大批量發(fā)短信的場(chǎng)景,如果使用單線(xiàn)程將全部一千個(gè)號(hào)碼發(fā)送完畢的話(huà),大約需要103132ms,可見(jiàn)效率低下,耗費(fèi)時(shí)間較長(zhǎng)。

多線(xiàn)程發(fā)送短信中的一個(gè)核心要點(diǎn)是,將全部手機(jī)號(hào)碼拆分成多個(gè)組后,分配給每個(gè)線(xiàn)程進(jìn)行執(zhí)行。

兩個(gè)線(xiàn)程的示例
/**
 * 兩個(gè)線(xiàn)程發(fā)送
 *
 * @param phoneList
 * @return
 */
private long twoThreads(List phoneList) {
    long start = System.currentTimeMillis();
    List list1 = phoneList.subList(0, phoneList.size() / 2);
    List list2 = phoneList.subList(phoneList.size() / 2, phoneList.size());
    SendMsgExtendThread smet = threadOperation.new SendMsgExtendThread(list1);
    smet.start();
    SendMsgExtendThread smet1 = threadOperation.new SendMsgExtendThread(list2);
    smet1.start();
    return 0;
}
另一種數(shù)據(jù)分組方式
/**
 * 另外一種分配方式
 *
 * @param phoneList
 */
private void otherThread(List phoneList) {
    for (int threadNo = 0; threadNo < 10; threadNo++) {
        int numbersPerThread = 10;
        List list = phoneList.subList(threadNo * numbersPerThread, (threadNo * numbersPerThread) + 10);
        SendMsgExtendThread smet = threadOperation.new SendMsgExtendThread(list);
        smet.start();
        if (list.size() < numbersPerThread) {
            break;
        }
    }
}
線(xiàn)程池發(fā)送
/**
 * 線(xiàn)程池發(fā)送
 *
 * @param phoneList
 * @return
 */
private void threadPool(List phoneList) {
    for (int threadNo = 0; threadNo < THREAD_POOL_SIZE; threadNo++) {
        int numbersPerThread = 10;
        List list = phoneList.subList(threadNo * numbersPerThread, (threadNo * numbersPerThread) + 10);
        threadOperation.executorService.execute(threadOperation.new SendMsgExtendThread(list));
    }
    threadOperation.executorService.shutdown();
}
使用Callable發(fā)送
/**
 * 多線(xiàn)程發(fā)送
 *
 * @param phoneList
 * @return
 */
private void multiThreadSend(List phoneList) {
    List> futures = new ArrayList<>();
    for (int threadNo = 0; threadNo < THREAD_POOL_SIZE; threadNo++) {
        int numbersPerThread = 100;
        List list = phoneList.subList(threadNo * numbersPerThread, (threadNo * numbersPerThread) + 100);
        Future future = threadOperation.executorService.submit(threadOperation.new SendMsgImplCallable(list, String.valueOf(threadNo)));
        futures.add(future);
    }
    for (Future future : futures) {
        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
    threadOperation.executorService.shutdown();
}

使用多線(xiàn)程發(fā)送,將發(fā)送任務(wù)進(jìn)行分割然后分配給每個(gè)線(xiàn)程執(zhí)行,執(zhí)行完畢需要10266ms,可見(jiàn)執(zhí)行效率明顯提升,消耗時(shí)間明顯縮短。

完整代碼
package com.lingyejun.tick.authenticator;
 
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;
 
public class ThreadOperation {
 
    // 發(fā)短信的同步等待時(shí)間
    private static final long SEND_COST_TIME = 100L;
 
    // 手機(jī)號(hào)文件
    private static final String FILE_NAME = "/Users/lingye/Downloads/phone_number.xlsx";
 
    // 手機(jī)號(hào)列表
    private static List phoneList = new ArrayList<>();
 
    // 單例對(duì)象
    private static volatile ThreadOperation threadOperation;
 
    // 線(xiàn)程個(gè)數(shù)
    private static final int THREAD_POOL_SIZE = 10;
 
    // 初始化線(xiàn)程池
    private ExecutorService executorService = new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue());
 
    public ThreadOperation() {
        // 從本地文件中讀取手機(jī)號(hào)碼
        readFromExcel(FILE_NAME);
    }
 
    public static void main(String[] args) {
        ThreadOperation threadOperation = getInstance();
        //threadOperation.singleThread(phoneList);
        threadOperation.multiThreadSend(phoneList);
    }
 
    /**
     * 單例獲取對(duì)象
     *
     * @return
     */
    public static ThreadOperation getInstance() {
        if (threadOperation == null) {
            synchronized (ThreadOperation.class) {
                if (threadOperation == null) {
                    threadOperation = new ThreadOperation();
                }
            }
        }
        return threadOperation;
    }
 
    /**
     * 讀取Excel的文件信息
     *
     * @param fileName
     */
    public static void readFromExcel(String fileName) {
        InputStream is = null;
        try {
            is = new FileInputStream(fileName);
            XSSFWorkbook workbook = new XSSFWorkbook(is);
            XSSFSheet sheet = workbook.getSheetAt(0);
            int num = 0;
            // 循環(huán)行Row
            for (int rowNum = 0, lastNum = sheet.getLastRowNum(); rowNum <= lastNum; rowNum++) {
                XSSFRow row = sheet.getRow(rowNum);
                String phoneNumber = getStringValueFromCell(row.getCell(0)).trim();
                phoneList.add(phoneNumber);
            }
            System.out.println(num);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 讀取Excel里面Cell內(nèi)容
     *
     * @param cell
     * @return
     */
    private static String getStringValueFromCell(XSSFCell cell) {
 
        // 單元格內(nèi)的時(shí)間格式
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        // 單元格內(nèi)的數(shù)字類(lèi)型
        DecimalFormat decimalFormat = new DecimalFormat("#.#####");
        // 單元格默認(rèn)為空
        String cellValue = "";
 
        if (cell == null) {
            return cellValue;
        }
 
        // 按類(lèi)型讀取
        if (cell.getCellType() == XSSFCell.CELL_TYPE_STRING) {
            cellValue = cell.getStringCellValue();
        } else if (cell.getCellType() == XSSFCell.CELL_TYPE_NUMERIC) {
            // 日期轉(zhuǎn)為時(shí)間形式
            if (DateUtil.isCellDateFormatted(cell)) {
                double d = cell.getNumericCellValue();
                Date date = DateUtil.getJavaDate(d);
                cellValue = dateFormat.format(date);
            } else {
                // 其他轉(zhuǎn)為數(shù)字
                cellValue = decimalFormat.format((cell.getNumericCellValue()));
            }
        } else if (cell.getCellType() == XSSFCell.CELL_TYPE_BLANK) {
            cellValue = "";
        } else if (cell.getCellType() == XSSFCell.CELL_TYPE_BOOLEAN) {
            cellValue = String.valueOf(cell.getBooleanCellValue());
        } else if (cell.getCellType() == XSSFCell.CELL_TYPE_ERROR) {
            cellValue = "";
        } else if (cell.getCellType() == XSSFCell.CELL_TYPE_FORMULA) {
            cellValue = cell.getCellFormula().toString();
        }
        return cellValue;
    }
 
    /**
     * 外部接口耗時(shí)長(zhǎng),通過(guò)多線(xiàn)程增強(qiáng)
     *
     * @param userPhone
     */
    public void sendMsgToPhone(String userPhone) {
        try {
            Thread.sleep(SEND_COST_TIME);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("send message to : " + userPhone);
    }
 
    /**
     * 單線(xiàn)程發(fā)送
     *
     * @param phoneList
     * @return
     */
    private long singleThread(List phoneList) {
        long start = System.currentTimeMillis();
        /*// 直接主線(xiàn)程執(zhí)行
        for (String phoneNumber : phoneList) {
            threadOperation.sendMsgToPhone(phoneNumber);
        }*/
        SendMsgExtendThread smet = threadOperation.new SendMsgExtendThread(phoneList);
        smet.start();
        long totalTime = System.currentTimeMillis() - start;
        System.out.println("單線(xiàn)程發(fā)送總時(shí)間:" + totalTime);
        return totalTime;
    }
 
    /**
     * 另外一種分配方式
     *
     * @param phoneList
     */
    private void otherThread(List phoneList) {
        for (int threadNo = 0; threadNo < 10; threadNo++) {
            int numbersPerThread = 10;
            List list = phoneList.subList(threadNo * numbersPerThread, (threadNo * numbersPerThread) + 10);
            SendMsgExtendThread smet = threadOperation.new SendMsgExtendThread(list);
            smet.start();
            if (list.size() < numbersPerThread) {
                break;
            }
        }
    }
 
    /**
     * 兩個(gè)線(xiàn)程發(fā)送
     *
     * @param phoneList
     * @return
     */
    private long twoThreads(List phoneList) {
        long start = System.currentTimeMillis();
        List list1 = phoneList.subList(0, phoneList.size() / 2);
        List list2 = phoneList.subList(phoneList.size() / 2, phoneList.size());
        SendMsgExtendThread smet = threadOperation.new SendMsgExtendThread(list1);
        smet.start();
        SendMsgExtendThread smet1 = threadOperation.new SendMsgExtendThread(list2);
        smet1.start();
        return 0;
    }
 
    /**
     * 線(xiàn)程池發(fā)送
     *
     * @param phoneList
     * @return
     */
    private void threadPool(List phoneList) {
        for (int threadNo = 0; threadNo < THREAD_POOL_SIZE; threadNo++) {
            int numbersPerThread = 10;
            List list = phoneList.subList(threadNo * numbersPerThread, (threadNo * numbersPerThread) + 10);
            threadOperation.executorService.execute(threadOperation.new SendMsgExtendThread(list));
        }
        threadOperation.executorService.shutdown();
    }
 
    /**
     * 多線(xiàn)程發(fā)送
     *
     * @param phoneList
     * @return
     */
    private void multiThreadSend(List phoneList) {
        List> futures = new ArrayList<>();
        for (int threadNo = 0; threadNo < THREAD_POOL_SIZE; threadNo++) {
            int numbersPerThread = 100;
            List list = phoneList.subList(threadNo * numbersPerThread, (threadNo * numbersPerThread) + 100);
            Future future = threadOperation.executorService.submit(threadOperation.new SendMsgImplCallable(list, String.valueOf(threadNo)));
            futures.add(future);
        }
        for (Future future : futures) {
            try {
                System.out.println(future.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        threadOperation.executorService.shutdown();
    }
 
    public class SendMsgExtendThread extends Thread {
 
        private List numberListByThread;
 
        public SendMsgExtendThread(List numberList) {
            numberListByThread = numberList;
        }
 
        @Override
        public void run() {
            long startTime = System.currentTimeMillis();
            for (int i = 0; i < numberListByThread.size(); i++) {
                System.out.print("no." + (i + 1));
                sendMsgToPhone(numberListByThread.get(i));
            }
            System.out.println("== single thread send " + numberListByThread.size() + "execute time:" + (System.currentTimeMillis() - startTime) + " ms");
        }
    }
 
    public class SendMsgImplCallable implements Callable {
 
        private List numberListByThread;
 
        private String threadName;
 
        public SendMsgImplCallable(List numberList, String threadName) {
            numberListByThread = numberList;
            this.threadName = threadName;
        }
 
        @Override
        public Long call() throws Exception {
            Long startMills = System.currentTimeMillis();
            for (String number : numberListByThread) {
                sendMsgToPhone(number);
            }
            Long endMills = System.currentTimeMillis();
            return endMills - startMills;
        }
    }
}

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/77405.html

相關(guān)文章

  • (一)線(xiàn)程發(fā)展歷史

    摘要:從多線(xiàn)程的發(fā)展來(lái)看,可以操作系統(tǒng)的發(fā)展分為三個(gè)歷史階段真空管和穿孔卡片晶體管和批處理系統(tǒng)集成電路和多道程序設(shè)計(jì)最早的計(jì)算機(jī)只能解決簡(jiǎn)單的數(shù)學(xué)運(yùn)算問(wèn)題,比如正弦余弦等。我們用了比較長(zhǎng)的篇幅介紹了進(jìn)程線(xiàn)程發(fā)展的歷史。 專(zhuān)題簡(jiǎn)介 作為一個(gè)合格的Java程序員,必須要對(duì)并發(fā)編程有一個(gè)深層次的了解,在很多互聯(lián)網(wǎng)企業(yè)都會(huì)重點(diǎn)考察這一塊??赡芎芏喙ぷ?年以上的Java程序員對(duì)于這一領(lǐng)域幾乎沒(méi)有太多研...

    noONE 評(píng)論0 收藏0
  • 在瀏覽器中快速探測(cè)IP端口是否開(kāi)放

    摘要:探測(cè)端口開(kāi)放原理就是向目標(biāo)發(fā)送請(qǐng)求,看是否有回應(yīng)。端口判定為不通。掃描批量目標(biāo)掃描批量目標(biāo)使用的并發(fā)隊(duì)列功能,去執(zhí)行的執(zhí)行單個(gè)任務(wù),在掃描前做了一些額外的工作把瀏覽器屏蔽的端口過(guò)濾掉了,收到的狀態(tài)就是。 0×00 前言 前兩天 freebuf上的的XSS到內(nèi)網(wǎng)的公開(kāi)課很受啟發(fā),從一個(gè)頁(yè)面到局域網(wǎng),威力著實(shí)增強(qiáng)不少 公開(kāi)課上檢測(cè)內(nèi)網(wǎng) IP 實(shí)現(xiàn)方式用的是 img 標(biāo)簽,加載網(wǎng)站的 fav...

    jackwang 評(píng)論0 收藏0
  • 在瀏覽器中快速探測(cè)IP端口是否開(kāi)放

    摘要:探測(cè)端口開(kāi)放原理就是向目標(biāo)發(fā)送請(qǐng)求,看是否有回應(yīng)。端口判定為不通。掃描批量目標(biāo)掃描批量目標(biāo)使用的并發(fā)隊(duì)列功能,去執(zhí)行的執(zhí)行單個(gè)任務(wù),在掃描前做了一些額外的工作把瀏覽器屏蔽的端口過(guò)濾掉了,收到的狀態(tài)就是。 0×00 前言 前兩天 freebuf上的的XSS到內(nèi)網(wǎng)的公開(kāi)課很受啟發(fā),從一個(gè)頁(yè)面到局域網(wǎng),威力著實(shí)增強(qiáng)不少 公開(kāi)課上檢測(cè)內(nèi)網(wǎng) IP 實(shí)現(xiàn)方式用的是 img 標(biāo)簽,加載網(wǎng)站的 fav...

    jlanglang 評(píng)論0 收藏0
  • 消息隊(duì)列二三事

    摘要:但是我們明顯能感覺(jué)到這會(huì)降低吞吐量,因?yàn)橄⒉荒懿⑿型哆f了,而且會(huì)阻塞等待,也沒(méi)法發(fā)揮的威力。 最近在看kafka的代碼,就免不了想看看消息隊(duì)列的一些要點(diǎn):服務(wù)質(zhì)量(QOS)、性能、擴(kuò)展性等等,下面一一探索這些概念,并談?wù)勗谔囟ǖ南㈥?duì)列如kafka或者mosquito中是如何具體實(shí)現(xiàn)這些概念的。 服務(wù)質(zhì)量 服務(wù)語(yǔ)義 服務(wù)質(zhì)量一般可以分為三個(gè)級(jí)別,下面說(shuō)明它們不同語(yǔ)義。 At most...

    dack 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<