Runnable介面實現多線程 package Day23; //多線稱實現方式2() Runnable【介面】 public class RunnableDemo implements Runnable { //重寫此介面的run方法 @Override public void run() { f ...
Runnable介面實現多線程
package Day23; //多線稱實現方式2()----Runnable【介面】 public class RunnableDemo implements Runnable { //重寫此介面的run方法 @Override public void run() { for(int x=0;x<100;x++){ //public static Thread currentThread()返回對當前正在執行的線程對象的引用---返回當前執行的線程對象 //獲取當前線程對象的名稱---Thread.currentThread.getName System.out.println(Thread.currentThread().getName()); } } }
測試類
package Day23; /* * /* * 方式2:實現Runnable介面 * 步驟: * A:自定義類MyRunnable實現Runnable介面 * B:重寫run()方法 * C:創建MyRunnable類的對象 * D:創建Thread類的對象,並把C步驟的對象作為構造參數傳遞 */ public class RunnableTest { public static void main(String[] args) { //創建RunnableTest對象 RunnableDemo rbt = new RunnableDemo(); //public Thread(Runnable target,String name)分配新的 Thread 對象。 //target - 其 run 方法被調用的對象。 //name - 新線程的名稱。 Thread td = new Thread( rbt,"大海"); Thread td1= new Thread(rbt,"長江"); //使線程開始執行---虛擬機調用此方法 td.start(); td1.start(); } }
繼承類Thread--實現賣電影票
package cn.itcast_06; public class SellTicket extends Thread { // 定義100張票 // private int tickets = 100; // 為了讓多個線程對象共用這100張票,我們其實應該用靜態修飾 private static int tickets = 100; @Override public void run() { // 定義100張票 // 每個線程進來都會走這裡,這樣的話,每個線程對象相當於買的是自己的那100張票,這不合理,所以應該定義到外面 // int tickets = 100; // 是為了模擬一直有票 while (true) { if (tickets > 0) { System.out.println(getName() + "正在出售第" + (tickets--) + "張票"); } } } }
package cn.itcast_06; /* * 某電影院目前正在上映賀歲大片(紅高粱,少林寺傳奇藏經閣),共有100張票,而它有3個售票視窗售票,請設計一個程式模擬該電影院售票。 * 繼承Thread類來實現。 */ public class SellTicketDemo { public static void main(String[] args) { // 創建三個線程對象 SellTicket st1 = new SellTicket(); SellTicket st2 = new SellTicket(); SellTicket st3 = new SellTicket(); // 給線程對象起名字 st1.setName("視窗1"); st2.setName("視窗2"); st3.setName("視窗3"); // 啟動線程 st1.start(); st2.start(); st3.start(); } }
利用Runnable介面實現電影票的售票
package Day23; //使用Runnable介面實現電影票的銷售----3個視窗 public class Movie implements Runnable { //定義100張電影票 private int ticket =100; //重寫Runnable介面的run方法 @Override public void run() { while(true){ if (ticket>0){ //Runnable介面不能直接調用getName方法需要通過獲取當前線程來獲取名稱 System.out.println(Thread.currentThread().getName()+"正在銷售第" +(ticket--)+"張電影票"); } } } }
package Day23; //實現Runnable介面的多線程 public class MovieDemo { public static void main(String[] args) { //創建資源對象 Movie m = new Movie(); //創建三個線程對象 //給出運行的對象---並給出線程名稱 Thread m1 = new Thread(m,"視窗1"); Thread m2 = new Thread(m,"視窗2"); Thread m3 = new Thread(m,"視窗3"); //啟動線程 m1.start(); m2.start(); m3.start(); } }
解決線程安全問題----解決賣電影票程式問題
* 同步代碼塊:
* synchronized(對象){
* 需要同步的代碼;
* }
package cn.itcast_09; public class SellTicket implements Runnable { // 定義100張票 private int tickets = 100; //創建鎖對象 private Object obj = new Object(); // @Override // public void run() { // while (true) { // synchronized(new Object()){ // if (tickets > 0) { // try { // Thread.sleep(100); // } catch (InterruptedException e) { // e.printStackTrace(); // } // System.out.println(Thread.currentThread().getName() + "正在出售第" // + (tickets--) + "張票"); // } // } // } // } @Override public void run() { while (true) { synchronized (obj) { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "張票"); } } } } }
測試
package cn.itcast_09; /* * 如何解決線程安全問題呢? * * 要想解決問題,就要知道哪些原因會導致出問題:(而且這些原因也是以後我們判斷一個程式是否會有線程安全問題的標準) * A:是否是多線程環境 * B:是否有共用數據 * C:是否有多條語句操作共用數據 * * 我們來回想一下我們的程式有沒有上面的問題呢? * A:是否是多線程環境 是 * B:是否有共用數據 是 * C:是否有多條語句操作共用數據 是 * * 由此可見我們的程式出現問題是正常的,因為它滿足出問題的條件。 * 接下來才是我們要想想如何解決問題呢? * A和B的問題我們改變不了,我們只能想辦法去把C改變一下。 * 思想: * 把多條語句操作共用數據的代碼給包成一個整體,讓某個線程在執行的時候,別人不能來執行。 * 問題是我們不知道怎麼包啊?其實我也不知道,但是Java給我們提供了:同步機制。 * * 同步代碼塊: * synchronized(對象){ * 需要同步的代碼; * } * * A:對象是什麼呢? * 我們可以隨便創建一個對象試試。 * B:需要同步的代碼是哪些呢? * 把多條語句操作共用數據的代碼的部分給包起來 * * 註意: * 同步可以解決安全問題的根本原因就在那個對象上。該對象如同鎖的功能。 * 多個線程必須是同一把鎖。 */ public class SellTicketDemo { public static void main(String[] args) { // 創建資源對象 SellTicket st = new SellTicket(); // 創建三個線程對象 Thread t1 = new Thread(st, "視窗1"); Thread t2 = new Thread(st, "視窗2"); Thread t3 = new Thread(st, "視窗3"); // 啟動線程 t1.start(); t2.start(); t3.start(); } }
同步的特點:
* 前提:
* 多個線程
* 解決問題的時候要註意:
* 多個線程使用的是同一個鎖對象
* 同步的好處
* 同步的出現解決了多線程的安全問題。
* 同步的弊端
* 當線程相當多時,因為每個線程都會去判斷同步上的鎖,這是很耗費資源的,無形中會降低程式的運行效率。
同步代碼塊的鎖以及同步方法應用和鎖的問題
package cn.itcast_11; public class SellTicket implements Runnable { // 定義100張票 private static int tickets = 100; // 定義同一把鎖 private Object obj = new Object(); private Demo d = new Demo(); private int x = 0; //同步代碼塊用obj做鎖 // @Override // public void run() { // while (true) { // synchronized (obj) { // if (tickets > 0) { // try { // Thread.sleep(100); // } catch (InterruptedException e) { // e.printStackTrace(); // } // System.out.println(Thread.currentThread().getName() // + "正在出售第" + (tickets--) + "張票 "); // } // } // } // } //同步代碼塊用任意對象做鎖 // @Override // public void run() { // while (true) { // synchronized (d) { // if (tickets > 0) { // try { // Thread.sleep(100); // } catch (InterruptedException e) { // e.printStackTrace(); // } // System.out.println(Thread.currentThread().getName() // + "正在出售第" + (tickets--) + "張票 "); // } // } // } // } @Override public void run() { while (true) { if(x%2==0){ synchronized (SellTicket.class) { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "張票 "); } } }else { // synchronized (d) { // if (tickets > 0) { // try { // Thread.sleep(100); // } catch (InterruptedException e) { // e.printStackTrace(); // } // System.out.println(Thread.currentThread().getName() // + "正在出售第" + (tickets--) + "張票 "); // } // } sellTicket(); } x++; } } // private void sellTicket() { // synchronized (d) { // if (tickets > 0) { // try { // Thread.sleep(100); // } catch (InterruptedException e) { // e.printStackTrace(); // } // System.out.println(Thread.currentThread().getName() // + "正在出售第" + (tickets--) + "張票 "); // } // } // } //如果一個方法一進去就看到了代碼被同步了,那麼我就再想能不能把這個同步加在方法上呢? // private synchronized void sellTicket() { // if (tickets > 0) { // try { // Thread.sleep(100); // } catch (InterruptedException e) { // e.printStackTrace(); // } // System.out.println(Thread.currentThread().getName() // + "正在出售第" + (tickets--) + "張票 "); // } // } private static synchronized void sellTicket() { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "張票 "); } } } class Demo { }
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
* B:同步方法的格式及鎖對象問題?
* 把同步關鍵字加在方法上。
* 同步方法是誰呢?
* this----本類
package Day23; //使用Runnable介面實現電影票的銷售----3個視窗 /* * * 同步代碼塊: * synchronized(對象){ * 需要同步的代碼; * */ public class Movie implements Runnable { //定義100張電影票 private int ticket =100; //定義一個鎖對象 private Object obj = new Object(); private int x =0; //重寫Runnable介面的run方法 @Override public void run() { while(true) { if (x % 2 == 0) { synchronized (this) { if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //Runnable介面不能直接調用getName方法需要通過獲取當前線程來獲取名稱 System.out.println(Thread.currentThread().getName() + "正在銷售第" + (ticket--) + "張電影票"); } } } else { sellTicket(); } x++; } } private synchronized void sellTicket() { if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + (ticket--) + "張票 "); } } }
測試類
package Day23; //實現Runnable介面的多線程 public class MovieDemo { public static void main(String[] args) { //創建資源對象 Movie m = new Movie(); //創建三個線程對象 //給出運行的對象---並給出線程名稱 Thread m1 = new Thread(m,"視窗1"); Thread m2 = new Thread(m,"視窗2"); Thread m3 = new Thread(m,"視窗3"); //啟動線程 m1.start(); m2.start(); m3.start(); } }
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
* A:同步代碼塊的鎖對象是誰呢?
* 任意對象。
*
* B:同步方法的格式及鎖對象問題?
* 把同步關鍵字加在方法上。
*
* 同步方法是誰呢?
* this----本類
*
* C:靜態方法及鎖對象問題?
* 靜態方法的鎖對象是誰呢?
* 類的位元組碼文件對象。(反射會講)
*/
package cn.itcast_11; /* * A:同步代碼塊的鎖對象是誰呢? * 任意對象。 * * B:同步方法的格式及鎖對象問題? * 把同步關鍵字加在方法上。 * * 同步方法是誰呢? * this * * C:靜態方法及鎖對象問題? * 靜態方法的鎖對象是誰呢? * 類的位元組碼文件對象。(反射會講) */ public class SellTicketDemo { public static void main(String[] args) { // 創建資源對象 SellTicket st = new SellTicket(); // 創建三個線程對象 Thread t1 = new Thread(st, "視窗1"); Thread t2 = new Thread(st, "視窗2"); Thread t3 = new Thread(st, "視窗3"); // 啟動線程 t1.start(); t2.start(); t3.start(); } }
以前線程安全類回顧
package cn.itcast_12; import java.util.ArrayList; import java.util.Collections; import java.util.Hashtable; import java.util.List; import java.util.Vector; public class ThreadDemo { public static void main(String[] args) { // 線程安全的類 StringBuffer sb = new StringBuffer(); Vector<String> v = new Vector<String>(); Hashtable<String, String> h = new Hashtable<String, String>(); // Vector是線程安全的時候才去考慮使用的,但是我還說過即使要安全,我也不用你 // 那麼到底用誰呢? //Collections //public static <T> List<T> synchronizedList(List<T> list)返回指定列表支持的同步(線程安全的)列表 List<String> list1 = new ArrayList<String>();// 線程不安全 List<String> list2 = Collections .synchronizedList(new ArrayList<String>()); // 線程安全 } }