多線程

  • 進程:一個操作系統(tǒng)中可以同時運行多個任務(wù)(程序)。系統(tǒng)級別上的多線程(多個任務(wù))跪呈,每個任務(wù)就叫做一個進程段磨。
  • 線程:一個程序同時可能運行多個任務(wù)。那么每個任務(wù)就叫做一個線程耗绿。
  • 并發(fā):線程是并發(fā)運行的薇溃。操作系統(tǒng)將時間劃分為若干個片段(時間片),盡可能的均勻分配給每一個任務(wù)缭乘,被分配時間片后沐序,任務(wù)有機會被cpu所執(zhí)行琉用。隨著cpu高效的運行,宏觀上看所有任務(wù)都在運行策幼。但微觀上看邑时,每個任務(wù)都是走走停停的。這種現(xiàn)象稱之為并發(fā)特姐。

Thread類——線程類

  • thread類的實例代表一個并發(fā)任務(wù)晶丘。
    并發(fā)的任務(wù)邏輯是通過重寫Thread的run方法實現(xiàn)的。
  • 線程調(diào)度:線程調(diào)度機制會將所有并發(fā)任務(wù)做統(tǒng)一的調(diào)度工作唐含,劃分時間片(可以被cpu執(zhí)行的時間)給每一個任務(wù)浅浮,時間片盡可能均勻,但做不到絕對均勻捷枯。同時滚秩,被分配時間片后,該任務(wù)被cpu執(zhí)行淮捆,但調(diào)度的過程中不能保證所有任務(wù)都是平均的獲取時間片的次數(shù)郁油。只能做到盡可能平均。這兩個都是程序不可控的攀痊。
/**
 * 線程
 *
 * 實現(xiàn)線程需要兩步
 * 1:繼承自Thread
 * 2:重寫run方法
 * run方法中應(yīng)該定義我們需要并發(fā)執(zhí)行的任務(wù)邏輯
 */

public class MyFirstThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println(i);
        }
    }
}
public class MySecThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("你好"+i+"次");
        }
    }
}
  • 另一種創(chuàng)建線程的方式桐腌,將線程與執(zhí)行的邏輯分離開。因為有了這樣的設(shè)計苟径,才有了線程池案站。關(guān)注點在于要執(zhí)行的邏輯。
  • Runnable接口:
    用于定義線程要執(zhí)行的任務(wù)邏輯棘街。我們定義一個類實現(xiàn)Runnable接口嚼吞,這時我們必須重寫run方法。在其中定義我們要執(zhí)行的邏輯蹬碧。之后將Runnable交給線程去執(zhí)行舱禽。從而實現(xiàn)了線程與其執(zhí)行的任務(wù)分離開。
  • 解耦:線程與線程體解耦恩沽。打斷依賴關(guān)系
public class MyFirstRunnable implements Runnable {
    /**
     * run方法中定義線程要執(zhí)行的邏輯
     */
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println(i);
        }
    }
}
public class MySecRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("你好"+i+"次");
        }
    }
}
/**
 * 測試線程
 */

public class TestThread {
    public static void main(String[] args){
        /*測試并發(fā)操作多個任務(wù)*/
        Thread t1 = new MyFirstThread();
        Thread t2 = new MySecThread();
        /*啟動線程開始并發(fā)執(zhí)行任務(wù)
        * 注意誊稚!想并發(fā)操作不要直接調(diào)用run方法!而是調(diào)用線程的
        * start()方法啟動線程罗心。
        * */
        //t1.start();
        //t2.start();
        /*不要使用stop()方法來停止線程的運行里伯。這是不安全的操作
        * 想讓線程停止,應(yīng)該通過run方法的執(zhí)行完畢來進行自然結(jié)束
        * (可以通過加標志位的方式來讓run方法提前結(jié)束來停止線程)渤闷。
        * */
        //t1.stop();
        Runnable r1 = new MyFirstRunnable();
        Runnable r2 = new MySecRunnable();
        /*將兩個任務(wù)分別交給線程去并發(fā)處理
        * 將任務(wù)交給線程可以使用線程的重載構(gòu)造方法
        * Thread(Runnable runnable)
        * */
        Thread thread1 = new Thread(r1);
        Thread thread2 = new Thread(r2);
        //thread1.start();
        //thread2.start();
        /*使用匿名內(nèi)部類方式創(chuàng)建線程*/
        Thread td1 = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    System.out.println(i);
                }
            }
        };
        //實現(xiàn)Runnable接口的形式
        Thread td2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    System.out.println("你好"+i+"次");
                }
            }
        });
        td1.start();
        td2.start();
    }
}

線程休眠

/**
 * 線程睡眠阻塞
 * 阻塞:
 *      使當前線程放棄cpu時間疾瓮,進入阻塞狀態(tài)。在阻塞狀態(tài)的線程
 *      不會分配時間片飒箭。直到該線程結(jié)束阻塞狀態(tài)回到Runnable狀態(tài)
 *      方可再次獲得時間片來讓cpu運行(進入Running狀態(tài))
 */

public class ThreadSleep {
    public static void main(String[] args){
        /*
        * 讓當前線程主動進入阻塞狀態(tài)
        * Thread.sleep(long time)
        * 主動進入阻塞狀態(tài)time毫秒后回到Runnable狀態(tài)
        * */
        int i = 0;
        while (true){
            System.out.println(i+"秒");
            i++;
            try {
                /*
                * 使用Thread.sleep()方法阻塞線程時強制讓我們必須捕獲“中斷異忱堑纾”
                * 引發(fā)情況:
                *       當前線程處于Sleep阻塞期間蜒灰,被另一個線程
                *       中斷阻塞狀態(tài)時,當前線程會拋出該異常肩碟。
                * */
                //阻塞當前主線程
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
/**
 * 中斷異常演示:仿裝修小品
 */
public class InterruptedExceptionTest {
    public static void main(String[] args){
        /*
        * 林永健進入睡眠狀態(tài)
        *
        * 方法中定義的類叫做局部內(nèi)部類
        * 局部內(nèi)部類中若想引用當前方法的其它局部變量
        * (參數(shù)也是方法的局部變量)强窖,
        * 那么該變量必須是final的。
        * */
        final Thread lin = new Thread(){
            @Override
            public void run() {
                System.out.println("林:睡覺了削祈。翅溺。。");
                try {
                    Thread.sleep(1000000);
                } catch (InterruptedException e) {
                    System.out.println("林:干嘛呢髓抑!干嘛呢咙崎!干嘛呢!");
                    System.out.println("林:都破了相了");
                }
            }
        };
        lin.start();//啟動第一個線程
        Thread huang = new Thread(){
            @Override
            public void run() {
                System.out.println("黃:80一錘子吨拍,您說砸哪兒褪猛?");
                for (int i = 0; i < 5; i++) {
                    System.out.println("黃:80!");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("咣當!");
                System.out.println("黃:搞定密末!");
                lin.interrupt();//中斷第一個線程的阻塞狀態(tài)
            }
        };
        huang.start();//啟動第一個線程
    }
}

線程其它方法

/**
 * 線程的方法:
 * yield():放棄當次時間片,主動進入Runnable狀態(tài)
 * setPriority():設(shè)置線程優(yōu)先級
 * 優(yōu)先級越高的線程跛璧,理論上獲取cpu的次數(shù)就越多
 * 設(shè)置線程優(yōu)先級一定要在線程啟動前設(shè)置严里!
 */
public class ThreadOtherMethod {
    public static void main(String[] args){
        Thread t1 = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println("你是誰啊追城?");
                    Thread.yield();
                }
            }
        };
        Thread t2 = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println("我是修水管的刹碾。");
                    Thread.yield();
                }
            }
        };
        Thread t3 = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println("我是打醬油的");
                    Thread.yield();
                }
            }
        };
        t1.setPriority(Thread.MAX_PRIORITY);
        t2.setPriority(Thread.MIN_PRIORITY);
        t1.start();
        t2.start();
        t3.start();
    }
}

線程并發(fā)安全問題

多線程在訪問同一個數(shù)據(jù)時(寫操作),可能會引發(fā)不安全操作座柱。

  • volatile關(guān)鍵字:用volatile修飾的變量迷帜,線程在每次讀取變量的時候,都會從主內(nèi)存中讀取最新的值色洞;每次給變量賦值時戏锹,都會把線程工作區(qū)變量的值同步到主內(nèi)存。volatile用來進行原子性操作火诸。當變量n=n+1锦针、n++ 等,volatile關(guān)鍵字將失效置蜀,只有當變量的值和自身上一個值無關(guān)時對該變量的操作才是原子級別的奈搜,volatile才有效。
/**
 * 多線程并發(fā)安全問題
 *
 * synchronized關(guān)鍵字
 * 線程安全鎖
 * synchronized可以修飾方法也可以單獨作為語句塊存在
 * synchronized的作用是限制多線程并發(fā)同時訪問該作用域
 */
public class ThreadSecure {
    public static void main(String[] args){
        /*main這個靜態(tài)方法中只能訪問靜態(tài)內(nèi)部類盯荤,所有Bank要用static修飾馋吗,
        * 不用static修飾的話會提示
        * 'com.example.ThreadSecure.this' cannot be referenced from a static context錯誤
        * */
        /*
        * 創(chuàng)建銀行
        * 創(chuàng)建兩個Person線程實例,并發(fā)從當前銀行對象中訪問數(shù)據(jù)
        * */
        Bank bank = new Bank();
        /*下面這樣創(chuàng)建會提示
        'com.example.ThreadSecure.Bank' is not an enclosing class錯誤
        沒有靜態(tài)(static)修飾的類中類不能使用外部類進行.操作,
        必須用實例來進行實例化類中類秋秤。
        */
        //new Bank.Person();
        //非靜態(tài)內(nèi)部類的創(chuàng)建和調(diào)用類實例的方法類似宏粤,類實例.new 非靜態(tài)內(nèi)部類名();
        Bank.Person p1 = bank.new Person();
        Bank.Person p2 = bank.new Person();
        p1.start();
        p2.start();
    }
    static class Bank{
        int count = 10000;
        //取錢方法
        /*
        * synchronized修飾方法后脚翘,方法就不是異步的了,而是同步的了商架,
        * synchronized會為方法上鎖堰怨。
        *
        * synchronized同步塊
        * synchronized (Object)
        * {需要同步的代碼塊片段}
        * Object指的是要上鎖的對象,
        * 這里必須注意蛇摸!要確保所有線程看到的是同一個對象备图!否則起不到同步的效果!
        * */
        synchronized void getMoney(int money){
            synchronized (this){
                if (count==0){
                    throw new RuntimeException("余額為0");
                }
            /*try {
                Thread.sleep(60);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }*/
                Thread.yield();
                count-=money;
                System.out.println("當前余額"+count);
            }
        }
        /*線程里面代碼出錯且未捕獲異常赶袄,當前線程會被殺死揽涮,
        但程序還是繼續(xù)運行,程序不會退出*/
        class Person extends Thread{
            @Override
            public void run() {
                while (true){
                    getMoney(100);
                }
            }
        }
    }
}

后臺線程

/**
 * 后臺線程也稱為守護線程
 * 特點:
 *      當當前進程中所有前臺線程死亡后饿肺,后臺線程強制死亡蒋困。無論
 *      是否還在運行。
 */

public class DaemonThread {
    public static void main(String[] args){
        Thread rose = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("let me go!");
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("AAAAaaaaaaa......噗通敬辣!");
            }
        };
        Thread jack = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println("you jump!i jump雪标!");
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        jack.setDaemon(true);//設(shè)置守護線程,必須在線程啟動之前設(shè)置
        rose.start();
        /*在執(zhí)行完成main方法的主線程執(zhí)行完畢死亡后溉跃,
        接著rose線程執(zhí)行完畢相繼死亡村刨,這時前臺線程都死亡了,
        守護線程jack強制死亡*/
        jack.start();
    }
}
  • wait/notify方法
    這兩個方法不是線程Thread中定義的方法撰茎,這兩個方法定義在Object中嵌牺。這兩個方法的作用是用于協(xié)調(diào)線程工作的。wait/notify方法必須保證在synchronized塊里面龄糊,而且等待哪個對象上就在哪個對象上上鎖逆粹,通知等待的線程運行和通知synchronized塊上的對象就是等待時上鎖的那個對象。
public class ThreadCoordinate {
    public static void main(String[] args){
        /*
        * 創(chuàng)建銀行
        * 創(chuàng)建兩個Person線程實例炫惩,并發(fā)從當前銀行對象中訪問數(shù)據(jù)
        * */
        Bank bank = new Bank();
        Bank.Person p1 = bank.new Person();
        Bank.Person p2 = bank.new Person();
        p1.start();
        p2.start();
        /*p1和p2都在bank對象上等待了僻弹。進入了阻塞*/
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        bank.count=10000;
        System.out.println("銀行開門了");
        //bank初始化完畢了
        synchronized (bank){
            bank.notifyAll();//通知在銀行上等待的所有線程可以工作了
        }
    }
    static class Bank{
        //count這個私有變量為什么可以在ThreadCoordinate這個類的main方法中訪問?
        /*內(nèi)部類就相當于一個外部類的成員變量他嚷,所以可以直接訪問外部變量奢方,
        外部類不能直接訪問內(nèi)部類變量,必須通過創(chuàng)建內(nèi)部類實例的方法訪問爸舒。
        想不通的肯定是指內(nèi)部類的私有變量怎么可以被外部類訪問吧蟋字,
        按常規(guī),私有變量m只能在InnerClass里被訪問扭勉,
        但你要注意鹊奖,內(nèi)部類就相當于一個外部類的成員變量,舉個例子涂炎。
        class Outer{
            private int m;
            private class Inner{
                private int n;
                private int k;
            }
        }
        m和類Inner都是成員變量忠聚,他們之間是平等的设哗,唯一不同的
        就是Inner它是包裝了幾個成員變量比如n,k,也就是說m n k是平等的两蟀,
        區(qū)別在于訪問n k要通過Inner网梢,就是要建立Inner實例訪問n k
        */
        private int count;
        //取錢方法
        void getMoney(int money){
            synchronized (this){
                if (count==0){
                    throw new RuntimeException("余額為0");
                }
                Thread.yield();
                count-=money;
                System.out.println("當前余額"+count);
            }
        }
        class Person extends Thread{
            @Override
            public void run() {
                System.out.println("準備取錢,等待銀行開門赂毯!");
                synchronized (Bank.this){
                    try {
                        Bank.this.wait();//當前線程(Person)在銀行對象上等
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                while (true){
                    getMoney(100);
                }
            }
        }
    }
}

線程池

  • 線程若想啟動需要調(diào)用start()方法战虏。這個方法要做很多操作。要和操作系統(tǒng)打交道党涕,注冊線程等工作烦感,等待線程調(diào)度。
  • ExecutorService提供了管理終止線程池的方法膛堤。
  • 線程池的創(chuàng)建都是工廠方法手趣。我們不要直接去new線程池,因為線程池的創(chuàng)建還要做很多的準備工作肥荔。
  • Executors.newCachedThreadPool();
    可根據(jù)任務(wù)需要動態(tài)創(chuàng)建線程绿渣,來執(zhí)行任務(wù)。若線程池中有空閑的線程將重用該線程來執(zhí)行任務(wù)燕耿。沒有空閑的則創(chuàng)建新線程來完成任務(wù)拆祈。理論上池子里可以放int最大值個線程贱枣。線程空閑時長超過1分鐘將會被回收屎蜓。一般用于處理執(zhí)行時間比較短的任務(wù)翼悴。(第二常用
  • Executors.newFixedThreadPool();創(chuàng)建固定大小的線程池皆串。池中的線程是固定的呵晚。若所有線程處于飽和狀態(tài)矾芙,新任務(wù)將排隊等待假抄。(最常用
  • Executors.newScheduledThreadPool();
    創(chuàng)建具有延遲效果的線程池隧出√ぶ荆可將待運行的任務(wù)延遲指定時長后再運行。
  • Executors.newSingleThreadExecutor();
    創(chuàng)建單線程的線程池胀瞪。池中僅有一個線程针余。所有未運行的任務(wù)排隊等待。
import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * 服務(wù)端
 * 加入雙緩沖隊列凄诞,加快讀寫數(shù)據(jù)操作圆雁。
 * 雙緩沖隊列可以規(guī)定隊列存儲元素的大小。
 * 一旦隊列中的元素達到最大值帆谍,待插入的元素將等待伪朽。
 * 等待時間是給定的。當給定時間到了元素還沒有機會被放入隊列
 * 那么會拋出超時異常汛蝙。
 */

public class ServerDemo {
    public static void main(String[] args){
        System.out.println("服務(wù)器啟動中......");
        ServerDemo demo = new ServerDemo();
        demo.start();//連接服務(wù)器并通信
    }
    private ServerSocket socket;
    private int port = 8088;
    //線程池
    private ExecutorService threadPool;
    /*構(gòu)建ServerDemo對象時就打開服務(wù)器端口*/
    public ServerDemo(){
        try {
            /*
            * ServerSocket構(gòu)造對象要求我們傳入要打開的端口號
            * ServerSocket對象在創(chuàng)建的時候就向操作系統(tǒng)申請打開
            * 這個端口烈涮。
            * */
            socket = new ServerSocket(port);
            //創(chuàng)建50個線程的固定大小的線程池
            threadPool = Executors.newFixedThreadPool(50);   
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    /*
    * 開始服務(wù)
    * 等待接收客戶端的請求并與其通信
    * */
    public void start(){
        try {
            /*通過調(diào)用ServerSocket的accept方法朴肺,使服務(wù)器開始等待
            * 接收客戶端的連接。
            * 該方法是一個阻塞方法坚洽,監(jiān)聽8088端口是否有客戶端連接戈稿。
            * 直到有客戶端與其連接,否則該方法不會結(jié)束讶舰。
            * */
            while (true){
                System.out.println("等待客戶端連接......");
                Socket s = socket.accept();
                System.out.println("一個客戶端連接了鞍盗,分配線程去接待它");
                /*當一個客戶端連接了,就啟動一個線程去接待它*/
                //Thread clientThread = new Thread(new Handler(s));
                //clientThread.start();
                /*
                * 將線程體(并發(fā)的任務(wù))交給線程池
                * 線程池會自動將該任務(wù)分配給一個空閑線程去執(zhí)行绘雁。
                * */
                threadPool.execute(new Handler(s));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /*定義線程體橡疼。該線程的作用是與連接到服務(wù)器端的客戶端
    進行交互操作*/
    class Handler implements Runnable{
        //當前線程要進行通信的客戶端Socket
        private Socket socket;
        //通過構(gòu)造方法將客戶端的Socket傳入
        public Handler(Socket socket){
            this.socket = socket;
        }
        @Override
        public void run() {
            try {
                InputStream in = socket.getInputStream();
                OutputStream out = socket.getOutputStream();
                PrintWriter writer = new PrintWriter(out);
                BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                //先聽客戶端發(fā)送的信息
                String info = reader.readLine();//這里同樣會阻塞
                System.out.println(info);
                //發(fā)送信息給客戶端
                writer.println("你好!客戶端");
                writer.flush();
                info = reader.readLine();
                System.out.println(info);
                writer.println("再見庐舟!客戶端");
                writer.flush();
                socket.close();//關(guān)閉與客戶端的連接
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;

/**
 * MINA框架 開源的socket框架欣除。很多游戲服務(wù)器的通信框架全用它
 *
 * 客戶端
 */

public class ClientDemo {
    public static void main(String[] args){
        ClientDemo demo = new ClientDemo();
        demo.send();//連接服務(wù)器并通信
    }
    private Socket socket;
    /*
    * 建立連接并向服務(wù)器發(fā)送信息
    * 步驟:
    *       1:通過服務(wù)器的地址及端口與服務(wù)器連接
    *       創(chuàng)建Socket時需要以上兩個數(shù)據(jù)
    *       2:連接成功后可以通過Socket獲取輸入流和輸出流
    *       使用輸入流接收服務(wù)端發(fā)送過來的信息
    *       使用輸出流信息發(fā)送給服務(wù)端
    *       3:關(guān)閉連接
    * */
    public void send(){
        try {
            System.out.println("開始連接服務(wù)器");
            /*1、連接服務(wù)器
            * 一旦Socket被實例化挪略,那么它就開始通過給定的地址和
            * 端口號去嘗試與服務(wù)器進行連接历帚。
            * 這里的地址“l(fā)ocalhost”是服務(wù)器的地址
            * 8088端口是服務(wù)器對外的端口。
            * 我們自身的端口是系統(tǒng)分配的杠娱,我們無需知道挽牢。
            * */
            socket = new Socket("localhost",8088);
            /**
             * 和服務(wù)器通信(讀寫數(shù)據(jù))
             * 使用socket獲取輸入和輸出流
             */
            InputStream in = socket.getInputStream();
            OutputStream out = socket.getOutputStream();
            /*將輸出流變成處理字符串的緩沖字符輸出流*/
            PrintWriter writer = new PrintWriter(out);
            writer.println("你好!服務(wù)器摊求!");
            /*
            * 注意禽拔,寫到輸出流的緩沖區(qū)里了,并沒有真的發(fā)給服務(wù)器
            * 想真的發(fā)送就要做真實的寫操作室叉,清空緩沖區(qū)
            * */
            writer.flush();
            //將輸入流轉(zhuǎn)換為緩沖字符輸入流
            BufferedReader reader = new BufferedReader(
                    new InputStreamReader(in)
            );
            /*讀取服務(wù)器發(fā)送過來的信息*/
            String info = reader.readLine();//讀取服務(wù)器信息會阻塞
            System.out.println(info);
            writer.println("再見睹栖!服務(wù)器!");
            writer.flush();
            info = reader.readLine();
            System.out.println(info);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
  • 雙緩沖隊列:BlockingQeque:解決了讀寫數(shù)據(jù)阻塞問題茧痕。但是同時寫或讀還是同步的野来。
   //雙緩沖隊列
    private BlockingQueue<String> msgQueue;

            /*
            * 創(chuàng)建規(guī)定大小的雙緩沖隊列
            * LinkedBlockingQueue是一個可以不指定隊列大小的
            * 雙緩沖隊列。若指定大小踪旷,當達到峰值后曼氛,待入隊的將
            * 等待。理論上最大值為int最大值
            * */
            msgQueue = new LinkedBlockingQueue<String>(10000);
            /*
            * 創(chuàng)建定時器令野,周期性的將隊列中的數(shù)據(jù)寫入文件
            * */
            Timer timer =new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    try {
                        PrintWriter writer =
                                new PrintWriter(new FileWriter("log.txt",true));
                        //從隊列中獲取所有元素舀患,做寫出操作
                        String msg = null;
                        for (int i = 0; i < msgQueue.size(); i++) {
                            /*
                            * 參數(shù) 0:時間量
                            *         TimeUnit.MILLISECONDS:時間單位
                            * */
                            msg = msgQueue.poll(0, TimeUnit.MILLISECONDS);
                            if (msg==null){
                                break;
                            }
                            writer.println(msg);//通過輸出流寫出數(shù)據(jù)
                        }
                        writer.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            },0,500);

                String msg = null;
                while (true){
                    //循環(huán)讀取客戶端發(fā)送過來的信息
                    msg = reader.readLine();
                    if (info!=null){
                        //插入隊列成功返回true,失敗返回false气破。
                        //該方法會阻塞線程聊浅,若中斷會報錯!
                        boolean b = msgQueue.offer(msg,5,TimeUnit.SECONDS);
                    }
                }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市狗超,隨后出現(xiàn)的幾起案子弹澎,更是在濱河造成了極大的恐慌,老刑警劉巖努咐,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件苦蒿,死亡現(xiàn)場離奇詭異,居然都是意外死亡渗稍,警方通過查閱死者的電腦和手機佩迟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來竿屹,“玉大人报强,你說我怎么就攤上這事」叭迹” “怎么了秉溉?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長碗誉。 經(jīng)常有香客問我召嘶,道長,這世上最難降的妖魔是什么哮缺? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任弄跌,我火速辦了婚禮,結(jié)果婚禮上尝苇,老公的妹妹穿的比我還像新娘铛只。我一直安慰自己,他們只是感情好糠溜,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布淳玩。 她就那樣靜靜地躺著,像睡著了一般诵冒。 火紅的嫁衣襯著肌膚如雪凯肋。 梳的紋絲不亂的頭發(fā)上谊惭,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天汽馋,我揣著相機與錄音,去河邊找鬼圈盔。 笑死豹芯,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的驱敲。 我是一名探鬼主播铁蹈,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼众眨!你這毒婦竟也來了握牧?” 一聲冷哼從身側(cè)響起容诬,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎沿腰,沒想到半個月后览徒,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡颂龙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年习蓬,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片措嵌。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡躲叼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出企巢,到底是詐尸還是另有隱情枫慷,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布浪规,位于F島的核電站流礁,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏罗丰。R本人自食惡果不足惜神帅,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望萌抵。 院中可真熱鬧找御,春花似錦、人聲如沸绍填。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽讨永。三九已至滔驶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間卿闹,已是汗流浹背揭糕。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留锻霎,地道東北人著角。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像旋恼,于是被迫代替她去往敵國和親吏口。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容