黑馬程序員 java多線程筆記(二)

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

線程間通信 

其實就是多個線程在操作同一個資源但是操作的總舵不同,(採用單例設計模式可以保證資源位置)

加了同步後還不安全 要想到同步的前提條件(1 是不是兩個以上的線程2是不是多線程使用同一個鎖)

wait()和sleep()的區別

wait()是釋放資源 釋放鎖

線程間通信示例代碼


sleep() 釋放資源 不釋放鎖

wait() notify() notifyAll() 都是用在同步中,因爲要對持有監視器(鎖)的線程操作,所以要使用在同步中,因爲只有同步才具有鎖。

爲什麼這些操作線程的方法都要定義在object類中呢,

因爲這些方法在操作同步線程時,都必須要表示他們所操作線程只有鎖,只有同一個鎖上的被等待線程可以被同一個鎖上的notify喚醒,不可以對不同鎖上的線程進行喚醒,也就是說等待和喚醒必須是同一個鎖,而鎖可以是任意對象,而可以被任意對象都調用的方法定義在object中。

下列程序按 ctrl + C結束。

class Res
{
	String name;
	String sex;
	boolean flag = false; 
}
class Input implements Runnable
{
	private Res r;
	Input(Res r)
	{
		this.r=r;
	}
	public void run()
	{
		int x = 0;
		while(true)
		{
			synchronized(r)//多線程間通信 解決完全問題
			{
				if (r.flag)
				{
					try
					{
						r.wait(); //製造等待喚醒機制
					}
					catch (Exception e)
					{
					}
					if (x==0)
					{
						r.name="mike";
						r.sex="man";
					}
					else
					{
						r.name="lili";
						r.sex="woman";
					}
					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 (Exception e)
					{
					}
					System.out.println(r.name+"......"+r.sex);
					r.flag = false;
					r.notify();
				}
			}
		}
	}
}
class  InputOutputDemo
{
	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();
	
	}
}

jdk1.5中提供了多線程升級解決方案將同步的synchronized替換成現實的lock操作,將Object中的wait notify notifyAll替換了condition對象,該獨享一lock鎖進行獲取 下面是典型的生產者消費者問題,利用到了 升級後的多線程解決方案

運行時按ctrl + c 結束

import java.util.concurrent.locks.*; // 導入包 才能用lock 

class Resource
{
	private String name ;
	private int count = 1;
	private boolean flag = false;
	private Lock lock = new ReentrantLock(); 
	
	private Condition condition_pro = lock.newCondition();
	private Condition condition_con = lock.newCondition();

	public void set(String name)throws InterruptedException
	{
		lock.lock();// 上鎖
		try
		{
			while(flag)
				condition_pro.await();//一個進去之後 其餘的都擋住
			this.name = name+"--"+count++;
			System.out.println(Thread.currentThread().getName()+".....生產者.."+this.name);
			flag = true;// 讓取出
			condition_con.signal();//喚醒對方
			
		}
		finally    
		{
			lock.unlock();//這句必須要有,要釋放鎖。
		}
	}

	public void out()throws InterruptedException
	{
		lock.lock();
		try
		{
			while(!flag)
				condition_con.await();
			System.out.println(Thread.currentThread().getName()+"..消費者....."+this.name);
			flag = false;
			condition_pro.signal();
		}
		finally
		{
			lock.unlock();
		}
	}
	
}
class Consumer implements Runnable
{
	private Resource res;
	Consumer(Resource res)
	{
		this.res = res;
	}
	public void run()
	{
		while (true)
		{
			try
			{
				res.out();
			}
			catch (InterruptedException e)
			{
			}
		}
	}
}
class Producer implements Runnable
{
	private Resource res ;
	Producer(Resource res)
	{
		this.res = res;
	}
	public void run()
	{
		while (true)
		{
			try
			{
				res.set("+商品+");
			}
			catch (InterruptedException e)
			{

			}
		}
	}

}
class  PCD
{
	public static void main(String[] args) 
	{
		Resource r = new Resource();
		Producer pro = new Producer(r);
		Consumer con = new Consumer(r);

		Thread t1 = new Thread(pro);//倆生產者倆消費者
		Thread t2 = new Thread(pro);
		Thread t3 = new Thread(con);
		Thread t4 = new Thread(con);

		t1.start();
		t2.start();
		t3.start();
		t4.start();

	
	}
}
停止線程,

stop方法已經過時了,如何停止線程只有一種方法 就是run方法結束,開啓多線程運行,運行代碼通常都是循環結構,只要控制循環就可以讓run方法結束,也就是線程結束。 特殊情況 當線程處於了凍結狀態就不會讀取到標記,那麼線程就不會結束。 interrupt將處於凍結狀態的線程,強制到運行狀態中來,只有運行才能標記,interrupt是清楚線程的凍結狀態

當沒有指定的方式讓凍結狀態復活到運行狀態是,這是需要對凍結狀態進行清楚,強制讓線程回覆到運行狀態鍾來,這樣就可以操作標記讓線程結束。 Thread中提供了interrupt()方法。後臺線程的特點是開啓跟後臺線程一起爭奪線程資源當所有的前臺線程結束後,後臺線程會自動結束。 下例子中t1.setDaemon(true);這個方法就是把t1變成後臺線程隨着主線程的結束 t1自動結束。

class StopThread implements Runnable
{
	private boolean flag = true;
	public void run()
	{
		while (flag)
		{
			System.out.println(Thread.currentThread().getName()+"...run");
		}
	}
	public void changeflag()
	{
		flag = false;
	}
		
}
class  STD
{
	public static void main(String[] args) 
	{
		StopThread st = new StopThread();//開一對象
		Thread t1 = new Thread(st);//開啓兩個線程
		Thread t2 = new Thread(st);

		t1.setDaemon(true);//變成保護線程 注意此處不要寫錯字母順序 是daemon 
		t2.setDaemon(true);
		t1.start();
		t2.start();

		int num  = 0;

		while (true)
		{
			if (num++ == 60)
			{
				break;
			}
			System.out.println(Thread.currentThread().getName()+"...."+num);
		
		}
			
		
		
		System.out.println("over!");
	}
}


join方法

主線程在向下走的時候t1.join()表示 t1要cpu的執行權,這時候執行權在主線程裏面,主線程會把執行權釋放,此時主線程會處於凍結狀態,或者的線程跟t1爭奪執行權,有可能是t1跟其他線程交替執行,主線程在t1結束之後才能恢復,無論其他線程如何主線程恢復到運行狀態,主線程遇到誰的join就等誰,【誰讓主線程等,就等到死】

join的特點

當A線程執行到了B線程的join方法是,A就等待B線程執行完A纔會執行。

join可以用來臨時加入線程執行。

Thread.yield()方法是用來停止當前線程,執行其他線程可以用來平均、平衡執行其他線程,當某些代碼需要同時進行的時候可以用不同的線程進行封裝。

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


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