(一)線程同步java
實現生產者消費者問題來講明線程問題,舉例以下所示:
編程
/** * 生產者消費者問題 */ public class ProducerConsumer { /** * 主方法 */ public static void main(String[] args) { ProductBox pb = new ProductBox(); Producer p = new Producer(pb); Consumer c = new Consumer(pb); //根據消費者、生產者生成線程 Thread pThread = new Thread(p); Thread cThread = new Thread(c); pThread.setPriority(Thread.MAX_PRIORITY); pThread.start(); cThread.start(); } } /** * 產品對象 * @author johsnton678 */ class Product { int id; public Product(int id) { super(); this.id = id; } public String toString(){ return "Product:" + id; } } /** * 產品盒對象 * @author johnston678 */ class ProductBox { Product[] productbox = new Product[6]; int index = 0; public ProductBox() { super(); } //存入方法,將產品存入產品盒 public synchronized void push(Product p) { //判斷產品是否超出產品盒的最大容量,若是超出中則等待 while (index == productbox.length) { try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } this.notify(); productbox[index] = p; index ++; } //取出操做 public synchronized Product pop() { //若是產品數量爲零,這等待 while (index == 0) { try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } this.notify(); index --; return productbox[index]; } } /** * 生產者 * @author johnston678 */ class Producer implements Runnable { ProductBox productbox = null; public Producer(ProductBox productbox) { super(); this.productbox = productbox; } @Override public void run() { // TODO Auto-generated method stub for (int i=0; i<10; i++) { Product p = new Product(i); productbox.push(p); System.out.println("produce:" + p); try { Thread.sleep((int)(Math.random() * 200)); } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * 消費者 * */ class Consumer implements Runnable { ProductBox productbox = null; public Consumer(ProductBox productbox) { super(); this.productbox = productbox; } @Override public void run() { // TODO Auto-generated method stub for (int i=0; i<10; i++) { Product p = productbox.pop(); System.out.println("consume:" + p); try { Thread.sleep((int)(Math.random() * 1000)); } catch (InterruptedException e) { e.printStackTrace(); } } } }
其中須要注意的是java多線程之 wait(),notify(),notifyAll()方法:多線程
wait(),notify(),notifyAll()不屬於Thread類,而是屬於Object基礎類,也就是說每一個對像都有wait(),notify(),notifyAll()
的功能.由於都個對像都有鎖,鎖是每一個對像的基礎,固然操做鎖的方法也是最基礎了.
先看java doc怎麼說:
wait致使當前的線程等待,直到其餘線程調用此對象的 notify() 方法或 notifyAll() 方法。當前的線程必須擁有此對象監視器。該線程發佈對此監視器的全部權並等待,直到其餘線程經過調用 notify 方法,或 notifyAll 方法通知在此對象的監視器上等待的線程醒來。而後該線程將等到從新得到對監視器的全部權後才能繼續執行.dom
notify喚醒在此對象監視器上等待的單個線程。若是全部線程都在此對象上等待,則會選擇喚醒其中一個線程。直到當前的線程放棄此對象上的鎖定,才能繼續執行被喚醒的線程。此方法只應由做爲此對象監視器的全部者的線程來調用.ide
"當前的線程必須擁有此對象監視器"與"此方法只應由做爲此對象監視器的全部者的線程來調用"說明wait方法與notify方法必須在同步塊內執行,即synchronized(obj以內).this
調用對像wait方法後,當前線程釋放對像鎖,進入等待狀態.直到其餘線程(也只能是其餘線程)經過notify 方法,或 notifyAll.該線程從新得到對像鎖.
繼續執行,記得線程必須從新得到對像鎖才能繼續執行.由於synchronized代碼塊內沒有鎖是寸步不能走的,能夠寫成spa
public synchronized void push(Product p) { ..... this.wait(); } 或者是 public synchronized void push(Product p) { ..... synchronized(this){ this.wait(); } }
(二)線程的定時執行:線程
會用到java.util.Calendar和java.util.timer類,code
1.java.util.Calendar用來設定時間,java.util.timer定時執行對象
Calendar c = Calendar.getInstance();獲得calendar類,
c.setTime(Date)設定時間,或是c.set(year,month,day,hour,m,s);注意,顯示的月份比真實事件多一個月,咱們設定時要比真實時間剪掉一個月如:如今是5月,咱們定時的時候要寫4
2.
Timer time = new Timer();
Integer a = new Integer(0) ;
MyTime t = new MyTime();//繼承自TimerTask類,實現了run()方法,其中是日期的比較
//一秒後執行,每5秒執行一次
time.schedule(t, 1000,5000);
package thread; import java.util.Calendar; import java.util.Date; import java.util.Timer; import java.util.TimerTask; //數據類1 class Data1{ private static int age = 0; public static int getAge() { return age; } public static void setAge(int age) { Data1.age = age; } } //數據類2 class Data2{ private static int age = 0; public static int getAge() { return age; } public static void setAge(int age) { Data2.age = age; } } class T1 extends Thread{ @Override public void run(){ for (int i = 0; i < 100; i++) { System.out.println(); System.out.println("1 的年齡 :" + i); Data1.setAge(i); try { this.sleep(500); } catch (InterruptedException e) { } } } } class T2 extends Thread{ @Override public void run() { for (int i = 110; i < 11000; i++) { System.out.println("2 的年齡 :" + i); Data2.setAge(i); try { this.sleep(500); } catch (InterruptedException e) { } } } } class T3 extends Thread{ @Override public void run() { Timer time = new Timer(); Integer a = new Integer(0) ; MyTime t = new MyTime(); //一秒後執行,每5秒執行一次 time.schedule(t, 1000,5000); } } /** * 定時執行類,時間到後執行操做 * @author WangQun * */ class MyTime extends TimerTask{ @Override public void run() { // 質檢 Calendar c = Calendar.getInstance(); Date date =new Date();//設置當前日期 c.set(2010, 04, 17, 10,19);//設置定時時間 System.out.println("當前時間 : "+date); System.out.println("設定時間 : "+c.getTime()); //比較時間 if(date.compareTo(c.getTime()) < 0){ System.out.println("時間還沒到!"); }else if(date.compareTo(c.getTime()) == 0){ System.out.println("時間到了!"); }else if(date.compareTo(c.getTime()) > 0){ System.out.println("時間過了!"); } } } class ShangSu{ public static void main(String[] args)throws InterruptedException{ T3 t3 = new T3(); } }
3.time定時器的關閉
若是你使用的是JDK 5+,還有一個scheduleAtFixedRate模式能夠用,在這個模式下,Timer會盡可能的讓任務在一個固定的頻率下運行,舉例說明:在上面的例子中,咱們想讓MyTask在1秒鐘後,每兩秒鐘執行一次,可是由於java不是實時的(其實java實時性不好.....),因此,咱們在上個程序中表達的原義並不可以嚴格執行.若是咱們調用的是scheduleAtFixedRate,那麼,Timer會盡可能讓你的Task執行的頻率保持在2秒一次.運行上面的程序,假設使用的是scheduleAtFixedRate,那麼下面的場景就是可能的:1秒鐘後,MyTask 執行一次,由於系統繁忙,以後的2.5秒後MyTask 才得以執行第二次,而後,Timer記下了這個延遲,並嘗試在下一個任務的時候彌補這個延遲,那麼,1.5秒後,MyTask 將執行的三次."以固定的頻率而不是固定的延遲時間去執行一個任務"
package thread; import java.io.IOException; import java.util.Timer; /**//* * 本類給出了使用Timer和TimerTaske的主要方法,其中包括定製任務,添加任務 * 退出任務,退出定時器. * 由於TimerTask的status域是包級可訪問的,因此沒有辦法在java.util.包外 * 獲得其狀態,這對編程形成一些不便 .咱們不能判斷某個Task的狀態了. * */ public class T { public static void main(String[] args){ Timer timer = new Timer(); MyTask myTask1 = new MyTask("myTask-1"); MyTask myTask2 = new MyTask("myTask-2"); timer.schedule(myTask1, 1000, 2000); timer.scheduleAtFixedRate(myTask2, 2000, 3000); while (true){ try { byte[] info = new byte[1024]; int len = System.in.read(info); String strInfo = new String(info, 0, len, "GBK");//從控制檯讀出信息 System.out.println("strInfo:"+strInfo); if (strInfo.charAt(strInfo.length() - 1) == ' ') { strInfo = strInfo.substring(0, strInfo.length() - 2); } if (strInfo.startsWith("Cancel-1")) { myTask1.cancel();//退出單個任務 // 其實應該在這裏判斷myTask2是否也退出了,是的話就應該break.可是由於沒法在包外獲得 // myTask2的狀態,因此,這裏不能作出是否退出循環的判斷. } else if (strInfo.startsWith("Cancel-2")) { myTask2.cancel(); } else if (strInfo.startsWith("Cancel-All")) { timer.cancel();//退出Timer break; } else { // 只對myTask1做出判斷,偷個懶^_^ myTask1.setInfo("myTask-1"); myTask2.setInfo("myTask-2"); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } static class MyTask extends java.util.TimerTask { String info = "^_^"; public MyTask(String info) { this.info = info; } @Override public void run() { // TODO Auto-generated method stub System.out.println(info); } public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } } }
果真很方便吧^_^
下面給出一個複雜點的例子,其中告訴你們怎麼退出單個TimerTask,怎麼退出全部Task