Android 學習系列 - Java 多線程

Java 多線程

Thread

sample

class MyThread extends Thread {
    
    private String name;

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

    @Override
    public void run() {
        //.....
    }
 }

 class Main {
    public static void main(String[] args) {
        MyThread a = new MyThread('A');
        MyThread b = new MyThread('B');
        a.start();
        b.start();
    }
 }

start 方法不能重複調用, 重複調用會出現java.lang.IllegalThreadStateException異常html

Runnable

sample

class MyRunnable extend Runnable{
    public MyRunnable() {

    }

    @Override
    public void run() {

    }
 }

 class Main {
    public static void main(String[] args) {
        MyRunnable a = new MyRunnable('A');
        MyRunnable b = new MyRunnable('B');

        Thread demoa = new Thread(a);
        Thread demob = new Thread(b);

        demoa.start();
        demob.start();
    }
 }

關於選擇繼承Thread仍是實現Runnable接口?

其實Thread也是實現Runnable接口的:java

class Thread implements Runnable {
    //…
    public void run() {
        if (target != null) {
             target.run();
        }
    }
 }

Thread中的run方法調用的是Runnable接口的run方法。Thread和Runnable都實現了run方法,這種操做模式其實就是代理模式。多線程

Thread和Runnable的區別

若是一個類繼承Thread,則不適合資源共享。可是若是實現了Runable接口的話,則很容易的實現資源共享。ide

class MyThread implements Runnable{
 
    private int ticket = 5;  //5張票
 
    public void run() {
        for (int i=0; i<=20; i++) {
            if (this.ticket > 0) {
                System.out.println(Thread.currentThread().getName()+ "正在賣票"+this.ticket--);
            }
        }
    }
}
public class lzwCode {
     
    public static void main(String [] args) {
        MyThread my = new MyThread();
        new Thread(my, "1號窗口").start();
        new Thread(my, "2號窗口").start();
        new Thread(my, "3號窗口").start();
    }
}

實現Runnable接口比繼承Thread類所具備的優點:this

1):適合多個相同的程序代碼的線程去處理同一個資源
2):能夠避免java中的單繼承的限制
3):增長程序的健壯性,代碼能夠被多個線程共享,代碼和數據獨立。操作系統

主線程和子線程之間的關係

在java中,每次程序運行至少啓動2個線程。一個是main線程,一個是垃圾收集線程。由於每當使用java命令執行一個類的時候,實際上都會啓動一個JVM,每個jVM就是在操做系統中啓動了一個進程。線程

主線程也有可能在子線程結束以前結束。而且子線程不受影響,不會由於主線程的結束而結束。代理

// 休眠兩秒
    Thread.sleep(2000);

    // 強制加入
    thread.join();

    // 後臺線程
    thread.setDaemon(true);

    /**
     * @author Rollen-Holt 後臺線程
     * */
    class hello implements Runnable {
        // 雖然有一個死循環,可是程序仍是能夠執行完的。由於在死循環中的線程操做已經設置爲後臺運行了。
        public void run() {
            while (true) {
                System.out.println(Thread.currentThread().getName() + "在運行");
            }
        }
     
        public static void main(String[] args) {
            hello he = new hello();
            Thread demo = new Thread(he, "線程");
            demo.setDaemon(true);
            demo.start();
        }
    }


    // 優先級
    // 不要誤覺得優先級越高就先執行。誰先執行仍是取決於誰先去的CPU的資源。
    thread.setPriority(8);

    // 禮讓
    // 在線程操做中,也可使用yield()方法,將一個線程的操做暫時交給其餘線程執行。
    Thread.currentThread().yield();

同步和死鎖

/**
 * @author Rollen-Holt
 * */
class hello implements Runnable {
    public void run() {
        for(int i=0;i<10;++i){
            if(count>0){
                try{
                    Thread.sleep(1000);
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println(count--);
            }
        }
    }
 
    public static void main(String[] args) {
        hello he=new hello();
        Thread h1=new Thread(he);
        Thread h2=new Thread(he);
        Thread h3=new Thread(he);
        h1.start();
        h2.start();
        h3.start();
    }
    private int count=5;
}

 //【運行結果】:
 // 5
 
 // 4

 // 3

 // 2

 // 1

 // 0

 // -1

這裏出現了-1,顯然這個是錯的。應該票數不能爲負值。
若是想解決這種問題,就須要使用同步。所謂同步就是在統一時間段中只有有一個線程運行,其餘的線程必須等到這個線程結束以後才能繼續執行。code

使用線程同步解決問題

使用同步代碼塊同步方法htm

同步代碼塊

synchronized(同步對象){

        //須要同步的代碼

    }
/**
 * @author Rollen-Holt
 * */
class hello implements Runnable {
    public void run() {
        for(int i=0;i<10;++i){
            synchronized (this) {
                if(count>0){
                    try{
                        Thread.sleep(1000);
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                    System.out.println(count--);
                }
            }
        }
    }
 
    public static void main(String[] args) {
        hello he=new hello();
        Thread h1=new Thread(he);
        Thread h2=new Thread(he);
        Thread h3=new Thread(he);
        h1.start();
        h2.start();
        h3.start();
    }
    private int count=5;
}

同步方法

synchronized 方法返回類型方法名(參數列表){

    // 其餘代碼

 }
/**
 * @author Rollen-Holt
 * */
class hello implements Runnable {
    public void run() {
        for (int i = 0; i < 10; ++i) {
            sale();
        }
    }
 
    public synchronized void sale() {
        if (count > 0) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(count--);
        }
    }
 
    public static void main(String[] args) {
        hello he = new hello();
        Thread h1 = new Thread(he);
        Thread h2 = new Thread(he);
        Thread h3 = new Thread(he);
        h1.start();
        h2.start();
        h3.start();
    }
 
    private int count = 5;
}

死鎖

當多個線程共享一個資源的時候須要進行同步,可是過多的同步可能致使死鎖。

生產者,消費者問題

/*
 *麪包類,用於存放廚師生產的麪包
 */
public class Bread {
    private String producer;

    public Bread(String producer) {
        super();
        this.producer = producer;
    }

    @Override
    public String toString() {
        return producer;
    }
}


 /* 
 * 籃子類,用於存放麪包 
 * 籃子假定最多放10個麪包 
 */  
public class Basket {  
    private int index = 0;  
    private Bread[] arrayBread = new Bread[10];  
  
    /* 
     * 此方法用於往籃子裏扔麪包 每當廚師生成好一個麪包就往籃子裏邊扔 因爲當某一個廚師在往籃子扔麪包的過程(還沒扔完,可是麪包已經在籃子裏), 
     * 又有一個廚師要往籃子裏扔麪包。 若是這是籃子裏已經有9個麪包的話,最後一個廚師就不能在扔了。 
     * 因此須要給這個方法加把鎖,等一個廚師扔完後,另一個廚師才能往籃子裏扔。 
     */  
    public synchronized void push(int id, Bread bread) {  
        System.out.println("生成前籃子裏有面包:" + index + " 個");  
        // 當廚師發現籃子滿了,就在那裏不停的等着  
        while (index == arrayBread.length) {  
            System.out.println("籃子滿了,我開始等等。。。。。。");  
            try {  
                // 廚師(一個生產線程)開始不停等待  
                // 他須要等待顧客(一個消費線程)把它叫醒  
                this.wait();  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
  
        // 喚醒一個正在等待的線程,若是喚醒的線程爲生產線程,則又會進入等待狀態,  
        // 若是爲消費線程,則因生產線程生產了麪包的緣故,消費線程能夠進行消費  
        this.notify();  
        arrayBread[index] = bread;  
        index++;  
        System.out.println(bread);  
  
    }  
  
    /* 
     * 此方法用於往籃子裏拿麪包 加鎖緣由和上邊同樣 
     */  
    public synchronized Bread pop(int id) {  
        System.out.println("消費前籃子裏有面包:" + index + " 個");  
        while (index == 0) {  
            System.out.println("籃子空了,我開始等等。。。。。。");  
            try {  
                // 顧客(一個消費線程)開始不停等待  
                // 他須要等待廚師(一個生產線程)把它叫醒  
                this.wait();  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
  
        // 喚醒一個正在等待的線程,若是喚醒的線程爲消費線程,則又會進入等待狀態,  
        // 若是爲生產線程,則因生產線程消費了麪包的緣故,生產線程能夠進行生產  
        this.notify();  
        index--;  
        System.out.println("第" + id + "個顧客消費了 -->" + arrayBread[index]);  
        return arrayBread[index];  
    }  
}

/* 
 * 廚師類,用於生產麪包 
 */  
public class Kitchener implements Runnable {  
    private Basket basket;  
    private int id;  
  
    public Kitchener(int id,Basket basket) {  
        super();  
        this.id = id;  
        this.basket = basket;  
    }  
  
    @Override  
    public void run() {  
        //讓廚師生產10個麪包  
        for (int i = 1; i <= 10; i++) {  
            Bread bread = new Bread("第" + id + "個廚師生成的麪包");  
            basket.push(id,bread);  
              
              
            try {  
                Thread.sleep(1);  
            } catch (InterruptedException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
        }  
  
    }  
  
}  

/* 
 * 顧客類,用於消費麪包 
 */  
public class Customer implements Runnable {  
    private Basket basket;  
    private int id;  
    public Customer(int id,Basket basket) {  
        super();  
        this.id = id;  
        this.basket = basket;  
    }  
  
    @Override  
    public void run() {  
        // 讓顧客消費10個麪包  
        for (int i = 1; i <= 10; i++) {  
            basket.pop(id);  
            try {  
                Thread.sleep(2000);  
            } catch (InterruptedException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
        }  
  
    }  
  
}

public class Test {  
    public static void main(String[] args) {  
        Basket basket = new Basket();  
        // 兩個廚師兩個客戶  
        Kitchener kitchener1 = new Kitchener(1,basket);  
        Kitchener kitchener2 = new Kitchener(2,basket);  
        Customer customer1 = new Customer(1,basket);  
        Customer customer2 = new Customer(2,basket);  
        new Thread(kitchener1).start();  
        new Thread(kitchener2).start();  
        new Thread(customer1).start();  
        new Thread(customer2).start();  
    }  
  
}

名字和年齡對應錯誤了,

http://www.cnblogs.com/rollenholt/archive/2011/08/28/2156357.html

相關文章
相關標籤/搜索