開始整理線程之前,之前有個命令忘記整理了,先整理一下jar命令的使用 Jar包 其實可以理解是java的壓縮包方便使用,只要在classpath設置jar路徑即可資料庫驅動,ssh框架等都是以jar包體現的 打包方式一:將指定的class文件打入到jar包中jar cvf xxx.jar Xxx.c ...
開始整理線程之前,之前有個命令忘記整理了,先整理一下jar命令的使用
Jar包
其實可以理解是java的壓縮包
方便使用,只要在classpath設置jar路徑即可
資料庫驅動,ssh框架等都是以jar包體現的
打包方式一:將指定的class文件打入到jar包中
jar cvf xxx.jar Xxx.class yyy.class
打包方式二:將某個目錄下的所有文件打入到jar包中
jar cvf xxx.jar -C xxx/.
查看jar文件:
jar -tf xxx.jar
運行jar包中的類:
java -cp xxx.jar xx.xx.xx(完整的類名)
常用的jar命令參數:
c:創建壓縮文件
f:指定存檔名稱
v:顯示詳細信息
m:加入自定義清單
指定清單文件(xxx.jar/META-INF/MNIFEST.MF)的入口類
jar cvfe classess.jar com.zhaofan.PackagDemo1 classes/.
這樣我們就可以通過java -jar xxx.jar直接執行
線程
進程:運行時概念,運行的應用程式
線程:應用程式內部併發執行的代碼段,共用記憶體
這裡幾個關鍵詞
yield: 放棄cpu搶占權
join:等待指定的線程執行完
sleep:靜態方法,讓線程休眠毫秒數
daemo:守護線程
最簡單的線程代碼:
package study_java.ex9; public class ThreadDemo1 { public static void main(String[] args){ Mythread t1 = new Mythread(); t1.start(); } } class Mythread extends Thread{ public void run(){ while (true){ System.out.println("MyThread"); } } }
join的一個簡單實用例子:
package study_java.ex9; public class ThreadDemo2 { public static void main(String[] args){ Player p1 = new Player("aa",5000); Player p2 = new Player("bb",8000); Player p3 = new Player("cc",2000); Player p4 = new Player("dd",3000); p1.start(); p2.start(); p3.start(); p4.start(); try{ p1.join(); p2.join(); p3.join(); p3.join(); } catch (Exception e){ } System.out.println("人到了,開始玩游戲"); } } class Player extends Thread{ private String name; private int time; public Player(String name, int time){ this.name = name; this.time = time; } public void run(){ System.out.println("玩家:"+name + "出發了"); try{ Thread.sleep(time); } catch (Exception e){ } System.out.println("玩家:"+name + "到了"); } }
守護線程的一個使用例子
package study_java.ex9; import java.util.Date; public class ThraedDemo3 { public static void main(String[] args){ Room r1 = new Room("no1",15000); Waiter w1 = new Waiter(); //w1.setDaemon(true); 設置守護線程 r1.start(); w1.start(); } } class Room extends Thread{ private String no; private int time; public Room(String no, int time){ this.no = no; this.time = time; } public void run(){ System.out.println("no" + "號房間正在唱歌"); try{ Thread.sleep(time); } catch (Exception e){ } System.out.println("no" + "買單"); } } class Waiter extends Thread{ public Waiter(){ this.setDaemon(true); } public void run(){ while (true){ System.out.println(new java.util.Date()); try{ Thread.sleep(1000); } catch (Exception e){ } } } }
任何一個對象都可以是鎖,信號燈,其實就是一個參照物
一個鎖的代碼例子:
package study_java.ex9; public class ThreadDemo4 { public static void main(String[] args){ Saler s1 = new Saler("a1"); Saler s2 = new Saler("a2"); s1.start(); s2.start(); } } class Saler extends Thread{ // 鎖 static Object lock = new Object(); static int tickts = 100; private String name; public Saler(String name){ this.name = name; } public void run(){ while (true){ int tick = getTickts(); if (tick > 0){ System.out.println(name+":"+ tick); } else { return; } } } // 取票 public int getTickts(){ synchronized (lock){ int currTicket = tickts; tickts --; return currTicket; } } }
還有一種方法是:
public static synchronized int getTickts(){ int currTicket = tickts; tickts --; return currTicket; }
這樣也能實現鎖的機制,但是註意這裡必須是static
我們整理一個新的寫法,把票池單獨寫出來
public class ThreadDemo2 { public static void main(String[] args){ TicketPool pool = new TicketPool(); Saler s1 = new Saler("s1",pool); Saler s2 = new Saler("s2",pool); s1.start(); s2.start(); } } // 票池 class TicketPool { private int tickets = 100; // 從票池取票 public synchronized int getTickets(){ int ticket = tickets; tickets -= 1; return ticket; } } // 售票員 class Saler extends Thread{ private TicketPool pool = null; private String name; public Saler(String name, TicketPool tp){ this.name = name; this.pool = tp; } public void run(){ while (true){ int no = pool.getTickets(); if (no > 0 ){ System.out.println(name + ":" + no); } else { return; } } } }
兩個小的練習熟悉上面知識點的使用:
車過山洞的問題,山洞同時只允許一個車通過,現在有多輛車,不同的車通過的時間不同,代碼實現如下:
package study_java.ex11; public class CarCave { public static void main(String[] args){ Cave cave = new Cave(); Car car1 = new Car(cave,10000,"奧迪"); Car car2 = new Car(cave,8000,"賓士"); Car car3 = new Car(cave,6000,"寶馬"); Car car4 = new Car(cave,2000,"悍馬"); car1.start(); car2.start(); car3.start(); car4.start(); } } class Cave{ public synchronized void crossCar(Car car){ try{ System.out.println(car.name+":開始過山洞了"); Thread.sleep(car.time); System.out.println(car.name+":開始出山洞了"); } catch (Exception e){ } } } class Car extends Thread{ public Cave cave; public int time; public String name; public Car(Cave cave ,int time,String name){ this.cave = cave; this.time = time; this.name = name; } public void run(){ cave.crossCar(this); } }
第二個小練習是我們經常遇到的場景,取票問題,現在有一個取票機,但是有五十個人要取票,實現代碼如下:
package study_java.ex11; public class TicketDemo1 { public static void main(String[] args){ TicketMachine m = new TicketMachine(); for (int i=0;i<50;i++){ new Person(m,"tom"+i).start(); } } } // 取票機 class TicketMachine{ private int ticketNo = 1; // 列印票號 public synchronized int printTicktNo(){ int currTicketNo = ticketNo; ticketNo ++; return currTicketNo; } } class Person extends Thread{ private TicketMachine m; private String name; public Person(TicketMachine m,String name) { this.m = m; this.name = name; } public void run(){ int no = m.printTicktNo(); System.out.println(name+ ":" + no); } }
生產者消費者模型
通過上面的知識點,寫一個生產者好消費者模型
package study_java.ex11; import java.util.LinkedList; import java.util.List; public class PCDemo1 { public static void main(String[] args){ MyList myList = new MyList(); Productor p = new Productor(myList); Consumer c = new Consumer(myList); Consumer c2 = new Consumer(myList); Consumer c3 = new Consumer(myList); p.start(); c.start(); c2.start(); c3.start(); } } class MyList{ private int Max = 100; private List<Integer> list = new LinkedList<Integer>(); public void addLast(Integer i){ while (true){ synchronized (list){ if (list.size() < Max){ list.add(i); return; } } } } public Integer removeFirst(){ while (true){ synchronized (list){ if(!list.isEmpty()){ return list.remove(0); } } } } } class Productor extends Thread{ private MyList myList; public Productor(MyList myList){ this.myList = myList; } public void run(){ int i = 1; while (true){ myList.addLast(new Integer(i)); System.out.println("生產者生產了"+i+"號"); i++; } } } class Consumer extends Thread{ private MyList myList; public Consumer(MyList myList){ this.myList = myList; } public void run(){ while (true){ int no = myList.removeFirst(); System.out.println("消費者消費了"+no+"號"); } } }
生產者消費者而改進版本:
package study_java.ex11; import java.util.LinkedList; import java.util.List; public class PCDemo5 { public static void main(String[] args){ Pool pool = new Pool(); Producter p1 = new Producter(pool); Consumer c1 = new Consumer(pool); p1.start(); c1.start(); } } class Pool{ private List<Integer> list = new LinkedList<Integer>(); private int Max = 100; public void addLast(int n){ synchronized (this){ while (list.size() >= Max){ try{ this.wait(); } catch (Exception e){ e.printStackTrace(); } } list.add(new Integer(n)); this.notifyAll(); } } public int remove(){ synchronized (this){ while (list.size() == 0){ try{ this.wait(); } catch (Exception e){ e.printStackTrace(); } } int no = list.remove(0); this.notifyAll(); return no; } } } // 生產者 class Producter extends Thread{ private Pool pool; static int i = 1; public Producter(Pool pool){ this.pool = pool; } public void run(){ while (true){ pool.addLast(i++); System.out.println("生產者生產了"+i+"號"); } } } // 消費者 class Consumer extends Thread{ private Pool pool; public Consumer(Pool pool){ this.pool = pool; } public void run(){ while (true){ int no = pool.remove(); System.out.println("消費者消費了"+no+"號"); } } }
wait():讓當前線程進入到鎖對象的等待隊列里,同時釋放鎖旗標。這個方法是當前鎖對象的方法
wait這裡還可以添加參數wait(int n) :等待指定的時間片,等待隊列中的線程最多等待n毫秒
notify():這個方法是當前鎖對象的方法,註意這裡並不會釋放鎖
notifyAll():通知等待隊列中的所有線程都可以搶占cpu運行,通知需要獲得對象的監控權
sleep:當前CPU的搶占權,和鎖對象的監控權無關。
Thread.currentThread().getName():獲取當前線程名字
Thread.currentThread().setName():設置當前線程名字
priority:1-10從低到高,預設是5
Thread.currentThread().getPriority():設置當前線程優先順序
線程狀態:
BLOCKED: 阻塞
NEW:新建
RUNNABL:執行
TERMINATED:已經終止
TIMED_WAITING:限時等待
WAITING:等待
創建一個線程的另外一種方式:
實現Runnable介面
1. 子類覆蓋介面中的run方法
2. 通過Thread類創建線程,並將實現了Runnable介面的子類對象作為參數傳遞給Thread類的構造函數
3. Thread類對象調用start方法開啟線程
代碼例子如下:
package study_java.ex11; public class RunnableDemo1 { public static void main(String[] args){ MyRunnabl m = new MyRunnabl(); new Thread(m).start(); } } class MyRunnabl implements Runnable{ public void run(){ System.out.println("hello world"); } }
同步(synchronized)
synchronized(對象)
{
需要同步的代碼
}
同步的特點:
同步的前提是:
需要兩個或者兩個以上的線程
多個線程使用的同一個鎖
同步的弊端:
當線程相當多時,因為每個線程都會去判斷同步上的鎖,這是很耗費資源的,無形中會降低程式的額運行效率