1. 程式人生 > >Java 多線程(一)

Java 多線程(一)

rgs max private 調用 pro 一個人 sync star args

一、線程的理解

 1、同個應用中,多個任務同時進行。就像QQ聊天,打開一個聊天窗口就是一個線程。

 2、線程可以有多個,但cpu每時每刻只做一件事。由於cpu處理速度很快,我們就感覺是同時進行的。所以宏觀上,線程時並發進行的;從微觀角度看,線程是異步執行的。

 3、使用線程的目的是最大限度的利用cpu資源。想想QQ聊天的時候,如果沒有多線程,一個人的信息沒有發完另一個人的信息發不過來,會是什麽情況~!

二、java中使用線程

 1、創建線程

eg1:繼承Thread

class MyThread extends Thread{
    @Override
    public void run() {
     //code
    }
}

啟動線程方法:new MyThread().start();

eg2:實現Runnable接口

class MyRunnable implements Runnable {
    @Override
    public void run() {
        //code
    }
}

啟動線程方法:new Thread(new MyRunnable()).start();

 2、設置線程優先級

Thread t = new Thread(myRunnable);
t.setPriority(Thread.MAX_PRIORITY);//一共10個等級,Thread.MAX_PRIORITY表示最高級10
t.start();

 3、join,sleep,yield的用法與區別

  join方法:假如你在A線程中調用了B線程的join方法B.join();,這時B線程繼續運行,A線程停止(進入阻塞狀態)。等B運行完畢A再繼續運行。

  sleep方法:線程中調用sleep方法後,本線程停止(進入阻塞狀態),運行權交給其他線程。

  yield方法:線程中調用yield方法後本線程並不停止,運行權由本線程和優先級不低於本線程的線程來搶。(不一定優先級高的能先搶到,只是優先級高的搶到的時間長)

 4、結束線程(修改標示符flag為false來終止線程的運行)

技術分享圖片
public class ThreadTest {
    public static void main(String[] args) {
        A aa = new A();
        Thread tt = new Thread(aa);
        tt.start();

        try {
            Thread.sleep(5000);
        } catch (Exception e) {
            e.printStackTrace();
        }

        aa.shutDown();
    }
}

class A implements Runnable {
    private boolean flag = true;

    public void run() {
        while (flag) {
            System.out.println("AAAA");
        }
    }

    public void shutDown() {
        this.flag = false;
    }
}
技術分享圖片

 5、線程同步synchronized

  synchronized可以修飾方法,或者方法內部的代碼塊。被synchronized修飾的代碼塊表示:一個線程在操作該資源時,不允許其他線程操作該資源。

技術分享圖片
public class ThreadTest {

    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        new Thread(myRunnable).start();
        new Thread(myRunnable).start();
        new Thread(myRunnable).start();
        new Thread(myRunnable).start();
    }

}

class MyRunnable implements Runnable {
    private int i = 0;

    @Override
    public void run() {
        while (true) {
            sumNum();
        }
    }

    private synchronized void sumNum() {
        if (i < 100) {
            try {
                Thread.sleep(1000);
                i ++;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "--------"
                    + i);
        }
    }

}
技術分享圖片

 6、wait、notify、notifyAll的用法

  wait方法:當前線程轉入阻塞狀態,讓出cpu的控制權,解除鎖定。

  notify方法:喚醒因為wait()進入阻塞狀態的其中一個線程。

  notifyAll方法: 喚醒因為wait()進入阻塞狀態的所有線程。

  這三個方法都必須用synchronized塊來包裝,而且必須是同一把鎖,不然會拋出java.lang.IllegalMonitorStateException異常。

下面是一個生產者、消費者例子:

技術分享圖片
public class ProductConsumer {
    public static int i = 0;

    public static void main(String[] args) {
        ProductStack ps = new ProductStack();
        Product product = new Product(ps);
        new Thread(product).start();

        Consumer consumer = new Consumer(ps);
        new Thread(consumer).start();
    }

}

class Product implements Runnable {
    ProductStack ps = null; 
    Product(ProductStack ps) {
        this.ps = ps;
    }
    @Override
    public void run() {
        while (true) {
            if (ProductConsumer.i < 100) {
                ps.push();
            }else{
                break;
            }
        }
    }

}

class Consumer implements Runnable {
    ProductStack ps = null;
        Consumer(ProductStack ps) {
            this.ps = ps;
        }

    @Override
    public void run() {
        while (true) {
            if (ProductConsumer.i < 100) {
                ps.pop();
            }else{
                break;
            }
        }
    }

}

class ProductStack {
    boolean isPro = true;
    public synchronized void push() {
        if (!isPro) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        notifyAll();
        ProductConsumer.i++;
        System.out.print("第" + ProductConsumer.i + "個產品,生產者:"
                + Thread.currentThread().getName());
        isPro = false;
        try {
            Thread.sleep((int) Math.random() * 200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
    }

    public synchronized void pop() {
        if (isPro) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        notifyAll();
        System.out.println(",消費者:" + Thread.currentThread().getName());
        isPro = true;
        try {
            Thread.sleep((int) Math.random() * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Java 多線程(一)