Java 線程編程中的同步、重複、定時

(一)線程同步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

相關文章
相關標籤/搜索