多線程實現方式

進程與線程

進程是程序在處理機中的一次運行。一個進程既包括其所要執行的指令,也包括了執行指令所需的系統資源,不一樣進程所佔用的系統資源相對獨立。因此進程是重量級的任務,它們之間的通訊和轉換都須要操做系統付出較大的開銷。java

線程是進程中的一個實體,是被系統獨立調度和分派的基本單位。線程本身基本上不擁有系統資源,但它能夠與同屬一個進程的其餘線程共享進程所擁有的所有資源。因此線程是輕量級的任務,它們之間的通訊和轉換隻須要較小的系統開銷。編程

Java支持多線程編程,所以用Java編寫的應用程序能夠同時執行多個任務。Java的多線程機制使用起來很是方便,用戶只需關注程序細節的實現,而不用擔憂後臺的多任務系統。安全

Java語言裏,線程表現爲線程類。Thread線程類封裝了全部須要的線程操做控制。在設計程序時,必須很清晰地區分開線程對象和運行線程,能夠將線程對象看做是運行線程的控制面板。在線程對象裏有不少方法來控制一個線程是否運行,睡眠,掛起或中止。線程類是控制線程行爲的惟一的手段。一旦一個Java程序啓動後,就已經有一個線程在運行。可經過調用Thread.currentThread方法來查看當前運行的是哪個線程。網絡

線程建立的兩種方法

JAVA中建立線程能夠經過繼承Thread類和實現Runnable接口來建立一個線程。Runnable方式能夠避免Thread 方式因爲JAVA單繼承特性帶來的缺陷。Runnable的代碼能夠被多個線程(Thread實例)共享,適合於多個線程處理同一資源的狀況。多線程

方式一:繼承Threadide

class MyThread extends Thread{
   private int ticketsCont=5; //一共有5張火車票

    private String name; //窗口, 也便是線程的名字

    public MyThread(String name){
        this.name=name;
    }

    @Override
    public void run(){
        
        while(ticketsCont>0){
            ticketsCont--; //若是還有票,就賣掉一張票
            System.out.println(name+"賣掉了1張票,剩餘票數爲:"+ticketsCont);
        }
        
    }

}

public class TicketsThread
{
    public static void main(String args[]){
        
        //建立三個線程,模擬三個窗口賣票
        MyThread mt1=new MyThread("窗口1");
        MyThread mt2=new MyThread("窗口2");
        MyThread mt3=new MyThread("窗口3");

        //啓動三個線程,也便是窗口,開始賣票
        mt1.start();
        mt2.start();
        mt3.start();

    }
}

方式二:實現Runnable接口this

class MyThread2 implements Runnable
{
    private int ticketsCont=1000; //一共有5張火車票
    
    @Override
    public void run(){
        
            
            while(true){
                 synchronized(this){
                    if(ticketsCont<=0){
                        break;
                    }
                    ticketsCont--; //若是還有票,就賣掉一張票
                    
                    System.out.println(Thread.currentThread().getName()+"賣掉了1張票,剩餘票數爲:"+ticketsCont);
                    
                    /*try{
                        Thread.sleep(50);  //經過阻塞程序來查看效果
                    }
                    catch(Exception e){
                        System.out.println(e);
                    }*/

                }
            }
        
    }



    /*@Override  //不加同步鎖
    public void run(){
        while(ticketsCont>0){
            ticketsCont--; //若是還有票,就賣掉一張票
            System.out.println(Thread.currentThread().getName()+"賣掉了1張票,剩餘票數爲:"+ticketsCont);
        }
    }*/
}

public class TicketsRunnable
{
    public static void main(String args[]){
        
        MyThread2 mt=new MyThread2();
        //建立三個線程來模擬三個售票窗口
        Thread th1=new Thread(mt,"窗口1");
        Thread th2=new Thread(mt,"窗口2");
        Thread th3=new Thread(mt,"窗口3");

        //啓動三個線程,也便是三個窗口,開始賣票
        th1.start();
        th2.start();
        th3.start();
        

    }
}

  • 建立:新建一個線程對象,如Thread thd=new Thread()
  • 就緒:建立了線程對象後,調用了線程的start()方法(此時線程知識進入了線程隊列,等待獲取CPU服務 ,具有了運行的條件,但並不必定已經開始運行了)
  • 運行:處於就緒狀態的線程,一旦獲取了CPU資源,便進入到運行狀態,開始執行run()方法裏面的邏輯
  • 終止:線程的run()方法執行完畢,或者線程調用了stop()方法,線程便進入終止狀態
  • 阻塞:一個正在執行的線程在某些狀況系,因爲某種緣由而暫時讓出了CPU資源,暫停了本身的執行,便進入了阻塞狀態,如調用了sleep()方法

線程的分類

  • 用戶線程:運行在前臺,執行具備的任務程序的主線程,鏈接網絡的子線程等都是用戶線程
  • 守護線程:運行在後頭,爲其餘前臺線程服務。一旦全部用戶線程都結束運行,守護線程會隨JVM一塊兒結束工做。能夠經過調用Thread類的setDaemon(true)方法來設置當前的線程爲守護線程,該方法必須在start()方法以前調用,不然會拋出 IllegalThreadStateException異常。在守護線程中產生的新線程也是守護線程。不是全部的任務均可以分配給守護線程來執行,好比讀寫操做或者計算邏輯。

 

場景:一個主線程,一個守護線程,守護線程會在很長一段時間內向本地文件中寫入數據,主線程進入阻塞狀態等待用戶的輸入,一旦確認了用戶的輸入阻塞就會解除掉,主線程繼續運行直到結束,守護線程也會隨虛擬機一同結束。spa

import java.io.*;
import java.util.Scanner;

class Daemon  implements Runnable
{
    @Override
    public void run(){
        System.out.println("進入守護線程");
        try{
            writeToFile();
        }
        catch(Exception e){
            e.printStackTrace();
        }

        System.out.println("退出守護線程");
    }


    private void writeToFile() throws Exception{
            File filename=new File("F:/慕課網(imooc)/細說多線程之Thread VS Runnable/daemon.txt");
            OutputStream os=new FileOutputStream(filename,true);
            int count=0;
            while(count<999){
                os.write(("\r\nword"+count).getBytes());
                System.out.println("守護線程"+Thread.currentThread().getName()+"向文件中寫入word"+count++);
                Thread.sleep(1000);
            }
    }
}

public class DaemonThreadDemo
{
    public static void main(String args[]){
        System.out.println("進入主線程"+Thread.currentThread().getName());
        Daemon daemonThread=new Daemon();
        Thread thread =new Thread(daemonThread);
        thread.setDaemon(true);
        thread.start();

        Scanner sc=new Scanner(System.in);
        sc.next();

        System.out.println("退出主線程"+Thread.currentThread().getName());

        
    }
}

總結

建議使用Runnable這種方式建立線程。 程序中的同一資源指的是同一個Runnable對象。安全的賣票程序中須要加入同步synchronized。操作系統

相關文章
相關標籤/搜索