------- android培訓、java培訓、期待與您交流! ----------
多線程技術可以說是java中很重要的一個環節!
那麼如何創建一個線程一般有兩種方式:
1.繼承Thread類,複寫run方法
/*這是第一種方法開啓一個線程:去繼承Thread類
* 需要複寫run方法
* */
class threadFristDemo extends Thread
{
public void run()
{
for(int i=0;i<10;i++)
{
System.out.println("this is frist"+i);
}
}
}
2.繼承Runnable接口,複寫run方法
/*這是第二種方法開啓一個線程:去繼承Runnable接口
*需要複寫run方法
* */
class threadSecondDemo implements Runnable
{
public void run()
{
for(int i=0;i<10;i++)
{
System.out.println("this is second"+i);
}
}
}
那麼如何開啓線程呢?
//這裏也說一下一般開發都是繼承Runnable接口!因爲這樣的擴展性強。你可以讓你的類去做你想做的事!
//比如在繼承其他的類和接口!
/*這裏是開啓兩個線程的實例,無論什麼方法都必須去用start()開啓!
* */
public static void threadDemo_0()
{
new threadFristDemo().start();
new Thread(new threadSecondDemo()).start();
}
一般都是調用都是start()方法區開啓!千萬不要調用run就好比是函數調用!
2.多線程編程
主要的解決因素爲資源共享問題:1.可以用同步代碼塊
/*
* 該方法解決時用了同步代碼塊
class saleDemo implements Runnable
{
private static int ticket=100;
public void run() {
while(ticket>0)
{
show();
}
}
public synchronized void show()
{
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"----"+ticket--);
}
}
*/
2.可以用同步函數來解決:
class saleDemo implements Runnable
{
private static int ticket=100;
Object obj = new Object();
public void run() {
while(ticket>0)
{
synchronized(obj)//注意這裏能否用new Object()?不能,。這樣會創建多個匿名Object
{
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"----"+ticket--);
}
}
}
}
那麼主函數可與這樣寫:
public static void threadDemo_1()
{
new Thread(new saleDemo()).start();//這裏啓動了3個線程
new Thread(new saleDemo()).start();
new Thread(new saleDemo()).start();
System.out.println(Thread.activeCount());//獲取當前活動線程數!這裏顯示是4,也就是說還有一個主線程。
System.out.println(Thread.currentThread());//獲取當前線程的信息
System.out.println(Thread.currentThread().getName());//獲取當前線程名稱
}
這裏主要是由於線程的 資源共享問題的解決!
本例子雖然是創建了不同的對象,但是ticket爲static的,所以內存中只有一份!也可作爲demo
但是有一點不能驗證synchronized函數方法!原因?你懂得!
解決資源共享問題的方法有1.synchronized(new Object()){}代碼塊2.synchronized函數
要注意他們的鎖的不同!
3 .死鎖問題:該死鎖程序的主要前提是有兩個鎖!訪問統一資源!當你的鎖嵌套時會出現相互鎖的情況! 我們在開發的時候要避免死鎖!
public static void threadDemo_2()
{
deadLock dl = new deadLock();
new Thread(dl).start();
try {
Thread.sleep(100);//加不加這一句是出現死鎖的關鍵!
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(dl).start();
}
class deadLock implements Runnable
{
private int ticket = 1000;
private boolean flag = true;
Object o1 =new Object();
Object o2 =new Object();
public void run()
{
show();
}
public void show()
{
if(flag)
{
flag = false;
synchronized(o1)
{
System.out.println("t-o1");
synchronized(o2)
{
System.out.println("t-o1-02");
System.out.println(ticket--);
}
}
}
else
{
synchronized(o2)
{
System.out.println("f-02");
synchronized(o1)
{
System.out.println("f-02-01");
System.out.println(+ticket--);
}
}
}
}
}
這樣就會產生死鎖,我們分析一下原因是:由於鎖嵌套鎖導致的,也就是說當有一個資源同時被兩個鎖給鎖住了!
4.我們來看一個線程間通訊的例子,主要解決的問題是線程交替運行:
/*在生產和消費的問題中,最核心的就是數據共享和數據的交替使用!
* 數據共享可以用synchronized方法解決!
* 數據交換使用,可以用wait和notify來使用使得線程停止和解凍!
* 合理的使用函數就可以讓數據交替合理的出現和使用
* */
class res //定義一個資源
{
private String sal = null;//商品名稱
public static int count = 0; //商品編號
public boolean flag = false;//標誌位
//jdk1.5之後產生了Lock方法,有ReentrantLock產生一個對象!便可以用lock和unlock加減鎖
//而且可以有Condition對象,condition對象有await和singleAll方法
//使用十分方便!可以有單獨解鎖生產線程或消費線程的方法!
private Lock mylock;
private Condition cond_pro;
private Condition cond_con;
res()
{
this.mylock = new ReentrantLock();
this.cond_pro = mylock.newCondition();
this.cond_con = mylock.newCondition();
}
public void setSal(String sal)
{
this.sal =sal+count;
}
public String getSal()
{
return sal;
}
public void jdk5_pro()//jdk5.0之後的新方法
{
mylock.lock();
while(flag)
try {
cond_pro.await();//該方法的解凍必須由cond_pro.singleAll()來
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
setSal("mango");
System.out.println("pro----------"+getSal());
flag = true;
cond_con.signalAll();//只能解凍cond_con。await()的線程
mylock.unlock();
}
public void jdk5_con()
{
mylock.lock();
while(!flag)
try {
cond_con.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("con_eat:"+getSal());
flag = false;
cond_pro.signalAll();
mylock.unlock();
}
public synchronized void pro_sal()//生產方法
{
while(flag)//如果是1 個生產者就可以用if來判斷
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
setSal("mango");
System.out.println("pro----------"+getSal());
flag = true;
this.notifyAll();//喚醒線程池中的全部等待線程
}
public synchronized void con_sal()//消費方法
{
while(!flag)//如果是1個消費者者就可以用if來判斷
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("con_eat:"+getSal());
flag = false;
this.notifyAll();
}
}
//生產者類
class pro implements Runnable
{
private res r;//做一個共享資源!
pro(res r)
{
this.r = r;
}
@Override
public void run()
{
while(r.count<100)
r.jdk5_pro();
}
}
//消費者類
class consumer implements Runnable
{
private res r;
consumer(res r)
{
this.r = r;
}
@Override
public void run()
{
while(r.count<100)
{
r.jdk5_con();
}
}
}
這些代碼中有兩種產生方式:1.jdk1.5之前我們用wait和notify。2jdk1.5之後的Lock和Condition方式。
public static void main(String[] args) {
res r = new res();
pro p =new pro(r);
consumer c =new consumer(r);
new Thread(p).start();//注意的是兩個線程通信和多個線程通訊時不同的
new Thread(p).start();
new Thread(c).start();
new Thread(c).start();
}
這是主函數的開啓。代碼中我們可以看出Lock鎖更加方便,而且Condition對象可以分別解凍結狀態!
注意幾個線程函數:
1.interrupted()方法是把那些凍結狀態的線程解凍!併產生一個異常
2.setDaemon()是把該線程設爲守護線程,在沒有其他線程存在時jvm不會管守護線程。
該方法必須在調用start之前!
3.join()是爲了讓別的等待他終止!如t1.join時候,必須等t1調用完事之後再執行其他!
4.yield()釋放執行權
------- android培訓、java培訓、期待與您交流! ----------