Java 多線程(一)
一、線程的理解
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 多線程(一)