黑馬程序員_Java基礎_多線程

------- android培訓java培訓、期待與您交流! ----------

 一.主線程是負責Java程序執行,它存在與mian方法中
 *  jvm啓動不止一個線程,還有負責垃圾回收機制的線程
 *
 * Thread類是java對線程的封裝,API中說明只需要繼承這個類就能實現一個線程。
 *
 * 創建線程的第一種方式,就是繼承Thread類
 * 步驟:1.定義類繼承Thread
 *                 2.重寫Thread類中的run方法
 *                         目的:將自定義的代碼存儲到run方法中,讓線程運行
 *
 *               3.調用線程的start方法(作用:啓動線程,調用run方法)


 創建線程的第二種方式:實現Runnable接口

 步驟
      1,定義類實現Runnable接口
      2,覆蓋Runnable接口中的run方法
          將線程要運行的代碼放到該run方法中
      3,通過Thread類建立線程對象
      4,將Runnable接口的子類對象作爲實際參數傳遞給Thread類的構造函數(爲了放線程去指定對象的run方法)
      5,調用Thread類的start方法開啓線程,並調用Runnable接口子類的run方法



 實現方式和繼承方式有什麼區別?

 實現方式好處:避免了單繼承的侷限性,我們建議使用實現方式進行定義線程。
 區別:   繼承Thread:線程代碼存放在Thread子類的run方法中
 實現Runnable:線程代碼存放在接口的子類的run方法中。
 


 * 通過結果:運行的結果每次都是不同的。
 *                         因爲多個線程都在獲取cpu的執行權,cpu執行到誰,就運行誰。
 *
 * 結論:cpu執行過程中的某一時刻,只能有一個程序在運行(多核除外)
 *                 執行時間由cpu決定。
 *   
 * 多線程的特性:隨機性。
 *
 * 常用方法:static Thread currentThread()獲取當前線程對象
 *                  getName();獲取線程名稱
 *
 * 設置線程名稱:setName或者構造函數


 多線程安全問題:常見問題,當多條語句在操作同一個線程共享數據是,一個線程對多條語句只執行了一部分
 還沒執行完,另外一個線程參與進來執行,導致共享數據的錯誤。

 解決辦法:
 對多條操作共享數據的語句,只能讓一個線程都執行萬,在執行過程中,其他線程不可以參與。


 Java對於多線程的安全問題提供了專業的解決方式(同步代碼):
 synchronized(對象){
   需要同步的代碼;
 }

 對象如同鎖,持有鎖的線程可以在同步中執行,沒有鎖的線程即使得到cpu執行權,也進不去,因爲沒有獲取鎖


 如何停止線程?
 方法:只有一種方法,run方法結束。(stop方法已經過時)
 開啓多線程運行,運行代碼通常是循環結構

 要讓線程結束只有控制循環

 特殊情況:
 當線程處於凍結狀態
 就不會讀取到標記,那麼線程就不會結束
 

例子1:

class Demo extends Thread {
	
	public Demo(String name) {
		super(name);  //用於標識線程的名稱
	}
	public void run() {
		for (int i = 0; i <= 60; i++) {
			System.out.println(Thread.currentThread().getName()+"Demo run " + i);
		}
	}
}

public class ThreadDemo {
	
	public static void main(String[] args) {
		Demo d = new Demo("one-----");  //創建一個進程
		Demo b = new Demo("two-----");  //創建一個進程
		d.start();//開啓線程並執行該線程的run方法
		b.start();
	//  d.run();  僅僅是對象調用方法,而線程創建了,並沒有使用	
		
		for (int i = 0; i <= 60; i++) {
			System.out.println("Mian run " + i);
		}
		
	}

}


 同步的前提:
 1,必須要有兩個或者兩個以上的線程。
 2,必須是多個線程使用同一個鎖
 
同步好處:解決了多線程的安全問題
同步弊端:多個線程需要判斷鎖,比較消耗資源


例子2:

 需求:一個售票小程序

class Ticket implements Runnable {
	private static int tick = 100;
	Object obj = new Object();
	@Override
	public void run() {
		while (true) { // 注意 這裏會把資源耗盡的 小心哦
			synchronized (obj) {
				if (tick > 0) {
					try {
						Thread.sleep(10); // 休眠10毫秒
					} catch (InterruptedException e) {
					}
					System.out.println(Thread.currentThread().getName()
							+ "sale*********" + tick--);
				}
			}
		}
	}

}

public class TicketDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		// 開啓四個售票窗口
		Ticket tick = new Ticket();

		Thread t1 = new Thread(tick);
		Thread t2 = new Thread(tick);
		Thread t3 = new Thread(tick);
		Thread t4 = new Thread(tick);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}

}


例子3:


/*
 需求:銀行存錢,有兩個用戶分別存入300元,每次存入100,存3次
 
 多線程安全:多線程使用共享數據時,必須使用同步鎖,防止出現安全問題(synchronized)
 
 靜態的同步方法:使用的鎖是該方法所在類的字節碼文件對象。類名.class
 */

class Bank {
	private int sum;

	public synchronized void add(int n) {   //同步,使得多線程安全
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
		}
		sum = sum + n;
		System.out.println(Thread.currentThread().getName() + "---->sum:" + sum);
	}
}

class Cus implements Runnable{
	
	private Bank b = new Bank();

	@Override
	public void run() {
		for(int i =0 ; i<3 ;i++){
			b.add(100);
		}
		
	}
	
}

public class BankDemo {
	public static void main(String[] args) {

		Cus c = new Cus();
		
		//添加兩個線程
		Thread t1 = new Thread(c);
		Thread t2 = new Thread(c);
		t1.start();
		t2.start();
	}

}


例子4:

/*
 * 需求:兩個用戶,一個往數據庫中加入數據,一個向數據庫中申請讀出數據
 * 
 * 多線程通訊:要解決線程安全問題,使用到等待喚醒機制
 * 
 * wait();
 * notify();
 * notifyall();
 * 都是使用在同步中,因爲要對持有監視器(鎖)的線程操作
 * 所以要使用在同步中,因爲持有同步才具有鎖
 * 
 * 等待和喚醒必須是同一個鎖
 * 而鎖可以是任意對象,所有可以被任意對象調用的方法定義Object類中
 */

class Res{
	String name;
	String sex;
	boolean flag = false;
}
class Input implements Runnable{
	private Res r;
	public Input(Res r) {
		this.r = r;
	}
	@Override
	public void run() {
		int x= 0;
		while (true) {
			synchronized (r) {
				if(r.flag)
					try {
						r.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				if(x == 0)
				{
					r.name="make";
					r.sex="man";
				}
				else{
					r.name="麗麗";
					r.sex="女女女女女女";
				}
				x=(x+1)%2;
				r.flag=true;
				r.notify();
					
			}
		}
	}
}

class Output implements Runnable{
	private Res r;
	Output(Res r){
		this.r= r;
	}
	public void run(){
		while (true) {
			synchronized (r) {
				if(!r.flag)
					try {
						r.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				System.out.println(r.name + "........." + r.sex);
				r.flag=false;
				r.notify();
			}
		}
		
	}
}

public class InputOutputDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		Res r = new Res();
		Input in = new Input(r);
		Output out = new Output(r);
		
		Thread t1 = new Thread(in);
		Thread t2 = new Thread(out);
		t1.start();
		t2.start();
	}

}


例子5:
守護線程:當主線程執行完畢時,只剩下守護線程是,java 虛擬機會自動退出。

class StopThread implements Runnable {
	private boolean flag = true;

	@Override
	public synchronized void run() {

		while (flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				System.out.println(Thread.currentThread().getName()
						+ "++++Exception-----");
				flag = false;
			}
			System.out.println(Thread.currentThread().getName() + "run------");
		}
	}

	public void changeFlag() {
		flag = false;
	}
}

public class StopThreadDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		StopThread s = new StopThread();

		Thread t1 = new Thread(s);
		Thread t2 = new Thread(s);
		t1.setDaemon(true);  //標記線程爲守護線程,必須在啓動線程之前調用
		t2.setDaemon(true);
		t1.start();
		t2.start();

		int num = 0;
		while (true) {
			if (num++ == 60) {
//				s.changeFlag();
				t1.currentThread(); // 線程中斷:就是使處在凍結狀態的線程回到運行狀態
				t2.currentThread();
				break;
			}
			System.out.println(Thread.currentThread().getName() + "--main-----"+num);
		}
		System.out.println("over");
	}

}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章