我們到底能走多遠系列(6)
光陰似箭,我居然也到了需要相親的年齡。
我已經開始準備向人產生熟的階段前進,就像一個蘋果,從青苹果到成熟,要經曆很多,要面對很多,這一路,每一位在我身邊的朋友都有你的功勞。
加油,各位,我們都不孤單。
----------------------------------------------------------------
java多線程的一些理解:
關於同步方法,我們不得不需要記住:
1,線程在一個對象上,兩個線程不可以調用兩個不同的同步方法
2,當一個同步方法已經執行,其他線程還是能夠調用這個對象的非同步方法。
selvlet中為了提高響應速度,採用的是在初始化時將一個servlet執行個體化後放到一個Map中,當需要響應時直接從這個Map中取出執行個體用就可以了,如此即可提高反覆同時調用同個servlet時的回應時間。
而servlet本身多線程的,在對於同一個servlet的調用時,採用的是線程池的方式。(關於線程池,對於tomcat,可以再server.xm中通過<connector>元素在設定線程池中的數目)
所以,玩servlet的都應該明白:servlet是線程非安全的。
網上推薦的避免非安全的方式:
1,使用SingleThread,現在的servlet版本中已經被廢棄,可以無視。
2,同步共用資料的操作,在所有的多線程中多用得到。
3,不要使用執行個體變數,靜態變數
靜態變數是線程非安全的執行個體變數單例模式時是線程非安全的局部變數是安全執行緒的
----------------------------------------
多線程式控制制的精髓應該是控制共用資料從而控制多線程邏輯。
兩個線程輪流執行任務:
主程式:
public class MainTest { public static void main(String[] args) { FlgClass flgClass = new FlgClass();//共用資料 //兩個線程 Thread t1 = new Thread(new Thread1(flgClass)); Thread t2 = new Thread(new Thread2(flgClass)); t1.start(); t2.start(); }}
共用資料類:
//共用資料public class FlgClass { private boolean flg; public boolean isFlg() { return flg; } public void setFlg(boolean flg) { this.flg = flg; }}
兩個線程:
public class Thread1 implements Runnable { private FlgClass flgClass; Thread1(FlgClass flgClass) { this.flgClass = flgClass; } public void run() { int i = 5; synchronized (flgClass) { // 在一個迴圈中 while (i > 0) if (flgClass.isFlg()) { System.out.println(Thread.currentThread().getName() + " " + i); flgClass.setFlg(false);//控制共用資料從而控制線程邏輯 flgClass.notify(); --i; } else { try { flgClass.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } }}
public class Thread2 implements Runnable { private FlgClass flgClass; Thread2(FlgClass flgClass) { this.flgClass = flgClass; } public void run() { int i = 5; synchronized (flgClass) { while (i > 0) if (!flgClass.isFlg()) { System.out.println(Thread.currentThread().getName() + " " + i); flgClass.setFlg(true); flgClass.notify(); --i; } else { try { flgClass.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } }}
關於線程池:
//建立一個可重用固定線程數的線程池 ExecutorService pool = Executors.newFixedThreadPool(2);
//建立一個線程池,它可安排在給定延遲後運行命令或者定期地執行。 ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);
//建立等待隊列 BlockingQueue bqueue = new ArrayBlockingQueue(20); //建立一個單線程執行程式,它可安排在給定延遲後運行命令或者定期地執行。 ThreadPoolExecutor pool = new ThreadPoolExecutor(2,3,2,TimeUnit.MILLISECONDS,bqueue);
分工使現代社會進步!
做一個產品現在都是分工到很細,一個工人只要做好一件事就可以了,比如製造手機,一批工人只做手機螢幕,一批工人做外殼等等這樣分工後,提高了生產效率。
我想到傳送帶上的工作流程:一個工人焊接一個點後,產品就會傳下去,下一個工人焊接另一個點,知道最後一個工人拿到的是成品只需要封裝一下。
和前輩聊天的時候,他說像網路互動這種程式大多是這樣工作的。
所以我想學習下,一個簡單的流程模型
實現:
產品類:
/** * * 簡化的產品類 作為共用資料,是線程邏輯的操作對象 */public class Product { // 產品編號 private int id; // 用state來查看產品處在什麼階段 private int state; Product(int id, int state){ this.id = id; this.state = state; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getState() { return state; } public void setState(int state) { this.state = state; }}
主函數:
import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class PoolTest { public static void main(String[] args) { // 建立一個可重用固定線程數的線程池(生產者線程池) ExecutorService producerPool = Executors.newFixedThreadPool(3); // 封裝工人線程池(就是有3個封裝工人嘛) ExecutorService packerPool = Executors.newFixedThreadPool(3); // 有5分產品需要操作 Product p1 = new Product(1, 1); Product p2 = new Product(2, 1); Product p3 = new Product(3, 1); Product p4 = new Product(4, 1); Product p5 = new Product(5, 1); // 需要5個生產工人的活 producerPool.execute(new Producer(p1)); producerPool.execute(new Producer(p2)); producerPool.execute(new Producer(p3)); producerPool.execute(new Producer(p4)); producerPool.execute(new Producer(p5)); // 需要5個封裝工人的活 packerPool.execute(new Packer(p1)); packerPool.execute(new Packer(p2)); packerPool.execute(new Packer(p3)); packerPool.execute(new Packer(p4)); packerPool.execute(new Packer(p5)); // 關閉線程池 producerPool.shutdown();// 我想在shutdown的時候應該要檢查這個pool裡的線程都釋放了吧 packerPool.shutdown(); }}
生產線程:
public class Producer extends Thread { private Product product; Producer(Product product) { this.product = product; } @Override public void run() { synchronized (product) { while (true) { if (product.getState() == 1) { System.out.println(product.getId() + "號---進入生產階段---"); try { product.setState(2);// 標記下一個階段 sleep(500); System.out.println(product.getId() + "號---生產完畢---"); product.notify();// 釋放資源,相當於把生產好的產品傳送給下一個操作者-->封裝 } catch (InterruptedException e) { e.printStackTrace(); } } else if(product.getState() > 1){// 已經進入下一個階段 break;// 釋放線程 }else{// 在生產階段之前 try { product.wait(); // 產品還不能進入生產階段 } catch (InterruptedException e) { e.printStackTrace(); } } } } }}
封裝線程:
public class Packer extends Thread{ private Product product; Packer(Product product) { this.product = product; } @Override public void run() { synchronized (product) { while (true) { if (product.getState() == 2) { System.out.println(product.getId() + "號---進入封裝階段---"); try { product.setState(3);// 標記下一個階段 sleep(100); System.out.println(product.getId() + "號---封裝完畢---"); product.notify();// 釋放資源,相當於把封裝好的產品傳送給下一個階段 } catch (InterruptedException e) { e.printStackTrace(); } } else if(product.getState() > 2){// 已經進入下一個階段 break;// 釋放線程 }else{// 在封裝階段之前 try { product.wait(); // 產品還不能進入封裝階段 } catch (InterruptedException e) { e.printStackTrace(); } } } } }}
----------------------------------------------------------------------
努力不一定成功,但不努力肯定不會成功。
共勉。