新手學習多線程的詳細思路和流程


  最近在博客園中逛,看到多線程想學習一下,雖然作者本人感覺挺詳細的,但對於新手沒學過多線程理解還是有難度的,最多也就是明白大概意思,自己寫還是一片空白,我看過多個博客以后覺得還需要打代碼才能徹底理解多線程,以下以一個經典多線程題目為例,一個菜鳥解題的具體步驟:

  題目:建立三個線程,A線程打印10次A,B線程打印10次B,C線程打印10次C,要求線程同時運行,交替打印10次ABC。

  1.看到三個線程,同時運行,交替打印,和大神解答寫的各種流程、sleep、synchronized、wait、notify一陣頭痛。還是自己慢慢來,打印10個A先。。

 

package main;

/**
 * 
 * 多線程題目解答
 * @author 光
 * @version 2015年11月20日 上午10:46:53
 *
 */
public class ManyThreadPrint implements Runnable {
    
    public String name;
    
    public ManyThreadPrint(String name){
        this.name=name;
    }

    @Override
    public void run() {
        int count = 10;
        while(count > 0){
            System.out.print(name);
            count--;
        }
    }

    public static void main(String[] args) {
        ManyThreadPrint mtpa = new ManyThreadPrint("A");
        new Thread(mtpa).start();
    }
}

  解析:使用實現Runnable接口的方式使用線程,main方法中添加實例使用構造器傳參A,重寫run()方法中循環打印10次

  運行結果如下:

AAAAAAAAAA

  2.十次A打印完成,哈哈,把B和C打印以下試試

package main;

/**
 * 
 * 多線程題目解答
 * @author 光
 * @version 2015年11月20日 上午10:46:53
 *
 */
public class ManyThreadPrint implements Runnable {
    
    public String name;
    
    public ManyThreadPrint(String name){
        this.name=name;
    }

    @Override
    public void run() {
        int count = 10;
        while(count > 0){
            System.out.print(name);
            count--;
        }
    }

    public static void main(String[] args) {
        ManyThreadPrint mtpa = new ManyThreadPrint("A");
        ManyThreadPrint mtpb = new ManyThreadPrint("B");
        ManyThreadPrint mtpc = new ManyThreadPrint("C");
        new Thread(mtpa).start();
        new Thread(mtpb).start();
        new Thread(mtpc).start();
    }
}

  解析:只是在main方法中添加兩個實例把B和C穿進去,添加兩個線程執行

  運行結果如下:

AAAAAAAAAABBBBBBBBBBCCCCCCCCCC

  手賤又運行一下:

AAAAAAAAAACCCCCCCCCCBBBBBBBBBB

  這怎么回事。。在試一下:

ABBBBBBBBBBAAAAAAAAACCCCCCCCCC

  好吧,結果10個A,10個B,10個C全部打印出來了,就是結果不固定。

  3.查了一下資料,原來是3個線程同時執行,順序不固定。只好讓后面的線程先等一下再執行:

package main;

/**
 * 
 * 多線程題目解答
 * @author 光
 * @version 2015年11月20日 上午10:46:53
 *
 */
public class ManyThreadPrint implements Runnable {
    
    public String name;
    
    public ManyThreadPrint(String name){
        this.name=name;
    }

    @Override
    public void run() {
        int count = 10;
        while(count > 0){
            System.out.print(name);
            count--;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ManyThreadPrint mtpa = new ManyThreadPrint("A");
        ManyThreadPrint mtpb = new ManyThreadPrint("B");
        ManyThreadPrint mtpc = new ManyThreadPrint("C");
        new Thread(mtpa).start();
        Thread.sleep(10);
        new Thread(mtpb).start();
        Thread.sleep(10);
        new Thread(mtpc).start();
        Thread.sleep(10);
    }
}

  解析:有一點需要注意,Thread.sleep(10);是下一個線程啟動需要等待的時間,由於最后結果需要交替打印,所以第三個線程執行后也有一個等待,相當於下輪的第一個線程等待。

  結果如下(執行幾次都一樣):

AAAAAAAAAABBBBBBBBBBCCCCCCCCCC

  3.接下來就是交替ABC按照大神的方法,建立3個對象,雖然是三個普通的Object,卻在run()中通過同步、等待、釋放鎖來實現線程的執行順序,先看一下代碼:

package main;

/**
 * 
 * 多線程題目解答
 * @author 光
 * @version 2015年11月20日 上午10:46:53
 *
 */
public class ManyThreadPrint implements Runnable {
    
    public String name;
    public Object prev;
    public Object self;
    
    public ManyThreadPrint(String name, Object prev, Object self) {
        this.name = name;
        this.prev = prev;
        this.self = self;
    }


    @Override
    public void run() {
        int count = 10;
        while(count > 0){
            synchronized (prev) {
                synchronized (self) {
                    System.out.print(name);
                    count--;
                    self.notify();
                }
                try {
                    prev.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Object a = new Object(); 
        Object b = new Object();
        Object c = new Object();
        ManyThreadPrint mtpa = new ManyThreadPrint("A",c,a);
        ManyThreadPrint mtpb = new ManyThreadPrint("B",a,b);
        ManyThreadPrint mtpc = new ManyThreadPrint("C",b,c);
        new Thread(mtpa).start();
        Thread.sleep(10);
        new Thread(mtpb).start();
        Thread.sleep(10);
        new Thread(mtpc).start();
        Thread.sleep(10);
    }
}

  解析:

  改變構造器,每次創建實例是除了打印的字符串,還有兩個對象,這一點要注意,這兩個對象只是普通的Object,跟線程沒一毛線關系,只是通過線程對對象鎖的操作來控制流程。關鍵代碼在run()中的循環里面,一點一點來。

  這里synchronized (self)、synchronized (prev),self當前對象鎖,prev前一個(前綴)對象鎖,當線程獲取兩個對象鎖時執行打印;需要注意。將synchronized (self)放入synchronized (prev)中表示打印A線程執行后,進入等待前置C對象的線程池里面,這樣在打印C時喚醒一下C對象,那么打印C完成后就會立刻打印A,不過這樣執行需要保證3個線程的啟動順序,即main方法中的Thread.sleep(10)。啟動打印A線程時,打印A,喚醒自己,進入等待C的線程池,釋放AC。當3個線程按照啟動順序完成時,即打印C線程完成后,會立刻打印A,打印A線程完成后,立刻打印B,依照順序循環。

  也就是說,在3個線程啟動完成后,已經將打印A的線程進入等待C對象的線程池里;將打印B的線程進入等待A對象的線程池里;將打印C的線程進入等待B對象的線程池里。這時按照打印A線程、打印B線程、打印C線程的順序執行,就保證下一輪以打印A線程開始,從而保證以后打印順序。

  在自己打代碼的過程中發現了很多感覺看懂的時候沒發現的東西,所以,學東西,最好自己要手打一遍。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM