Java多線程--同步與死鎖:synchronized;等待與喚醒:wait、notify、notifyAll;生命周期
1、問題的引出

class MyThread implements Runnable{ private int ticket = 5 ; // 假設一共有5張票 public void run(){ for(int i=0;i<100;i++){ if(ticket>0){ // 還有票 try{ Thread.sleep(300) ; // 加入延遲 }catch(InterruptedException e){ e.printStackTrace() ; } System.out.println("賣票:ticket = " + ticket-- ); } } } }; public class SyncDemo01{ public static void main(String args[]){ MyThread mt = new MyThread() ; // 定義線程對象 Thread t1 = new Thread(mt) ; // 定義Thread對象 Thread t2 = new Thread(mt) ; // 定義Thread對象 Thread t3 = new Thread(mt) ; // 定義Thread對象 t1.start() ; t2.start() ; t3.start() ; } };



2、同步代碼塊


同步的時候,必須指明同步的對象,一般情況下會將當前對象作為同步對象,使用this表示。
class MyThread implements Runnable{ private int ticket = 5 ; // 假設一共有5張票 public void run(){ for(int i=0;i<100;i++){ synchronized(this){ // 要對當前對象進行同步 if(ticket>0){ // 還有票 try{ Thread.sleep(300) ; // 加入延遲 }catch(InterruptedException e){ e.printStackTrace() ; } System.out.println("賣票:ticket = " + ticket-- ); } } } } }; public class SyncDemo02{ public static void main(String args[]){ MyThread mt = new MyThread() ; // 定義線程對象 Thread t1 = new Thread(mt) ; // 定義Thread對象 Thread t2 = new Thread(mt) ; // 定義Thread對象 Thread t3 = new Thread(mt) ; // 定義Thread對象 t1.start() ; t2.start() ; t3.start() ; } };

3、同步方法

class MyThread implements Runnable{ private int ticket = 5 ; // 假設一共有5張票 public void run(){ for(int i=0;i<100;i++){ this.sale() ; // 調用同步方法 } } public synchronized void sale(){ // 聲明同步方法 if(ticket>0){ // 還有票 try{ Thread.sleep(300) ; // 加入延遲 }catch(InterruptedException e){ e.printStackTrace() ; } System.out.println("賣票:ticket = " + ticket-- ); } } }; public class SyncDemo03{ public static void main(String args[]){ MyThread mt = new MyThread() ; // 定義線程對象 Thread t1 = new Thread(mt) ; // 定義Thread對象 Thread t2 = new Thread(mt) ; // 定義Thread對象 Thread t3 = new Thread(mt) ; // 定義Thread對象 t1.start() ; t2.start() ; t3.start() ; } };
4、死鎖
過多的同步可能導致死鎖:死鎖表示在程序時,互相等待。
程序模擬:張三向李四要畫,用書交換;李四向張三要書,用畫交換。
class Zhangsan{ // 定義張三類 public void say(){ System.out.println("張三對李四說:“你給我畫,我就把書給你。”") ; } public void get(){ System.out.println("張三得到畫了。") ; } }; class Lisi{ // 定義李四類 public void say(){ System.out.println("李四對張三說:“你給我書,我就把畫給你”") ; } public void get(){ System.out.println("李四得到書了。") ; } }; public class ThreadDeadLock implements Runnable{ private static Zhangsan zs = new Zhangsan() ; // 實例化static型對象 private static Lisi ls = new Lisi() ; // 實例化static型對象 private boolean flag = false ; // 聲明標誌位,判斷那個先說話 public void run(){ // 覆寫run()方法 if(flag){ synchronized(zs){ // 同步張三 zs.say() ; try{ Thread.sleep(500) ; }catch(InterruptedException e){ e.printStackTrace() ; } synchronized(ls){ zs.get() ; } } }else{ synchronized(ls){ ls.say() ; try{ Thread.sleep(500) ; }catch(InterruptedException e){ e.printStackTrace() ; } synchronized(zs){ ls.get() ; } } } } public static void main(String args[]){ ThreadDeadLock t1 = new ThreadDeadLock() ; // 控製張三 ThreadDeadLock t2 = new ThreadDeadLock() ; // 控製李四 t1.flag = true ; t2.flag = false ; Thread thA = new Thread(t1) ; Thread thB = new Thread(t2) ; thA.start() ; thB.start() ; } };
5、Object類對線程的支持-----------喚醒和等待:notify、notifyAll、wait


線程操作經典案例程序:生產者和消費之問題,生產者不斷生產,消費者不斷取走生產者生產的產品。
加入等待與喚醒:

class Info{ // 定義信息類 private String name = "李興華"; // 定義name屬性 private String content = "JAVA講師" ; // 定義content屬性 private boolean flag = false ; // 設置標誌位 public synchronized void set(String name,String content){ if(!flag){ try{ super.wait() ; }catch(InterruptedException e){ e.printStackTrace() ; } } this.setName(name) ; // 設置名稱 try{ Thread.sleep(300) ; }catch(InterruptedException e){ e.printStackTrace() ; } this.setContent(content) ; // 設置內容 flag = false ; // 改變標誌位,表示可以取走 super.notify() ; } public synchronized void get(){ if(flag){ try{ super.wait() ; }catch(InterruptedException e){ e.printStackTrace() ; } } try{ Thread.sleep(300) ; }catch(InterruptedException e){ e.printStackTrace() ; } System.out.println(this.getName() + " --> " + this.getContent()) ; flag = true ; // 改變標誌位,表示可以生產 super.notify() ; } public void setName(String name){ this.name = name ; } public void setContent(String content){ this.content = content ; } public String getName(){ return this.name ; } public String getContent(){ return this.content ; } }; class Producer implements Runnable{ // 通過Runnable實現多線程 private Info info = null ; // 保存Info引用 public Producer(Info info){ this.info = info ; } public void run(){ boolean flag = false ; // 定義標記位 for(int i=0;i<50;i++){ if(flag){ this.info.set("李興華","JAVA講師") ; // 設置名稱 flag = false ; }else{ this.info.set("mldn","www.mldnjava.cn") ; // 設置名稱 flag = true ; } } } }; class Consumer implements Runnable{ private Info info = null ; public Consumer(Info info){ this.info = info ; } public void run(){ for(int i=0;i<50;i++){ this.info.get() ; } } }; public class ThreadCaseDemo03{ public static void main(String args[]){ Info info = new Info(); // 實例化Info對象 Producer pro = new Producer(info) ; // 生產者 Consumer con = new Consumer(info) ; // 消費者 new Thread(pro).start() ; new Thread(con).start() ; } };
6、線程的生命周期


class MyThread implements Runnable{ private boolean flag = true ; // 定義標誌位 public void run(){ int i = 0 ; while(this.flag){ System.out.println(Thread.currentThread().getName() +"運行,i = " + (i++)) ; } } public void stop(){ this.flag = false ; // 修改標誌位 } }; public class StopDemo{ public static void main(String args[]){ MyThread my = new MyThread() ; Thread t = new Thread(my,"線程") ; // 建立線程對象 t.start() ; // 啟動線程 try{ Thread.sleep(30) ; }catch(Exception e){ } my.stop() ; // 修改標誌位,停止運行 } };
最後更新:2017-04-03 14:53:40