程序: 程序是計算機指令的集合,它以文件的形式存儲在磁盤上。
進程:是一個程序在其自身的地址空間中的一次執行活動。進程是資源申請、調度和獨立運行的單位,因此,它使用系統中的運行資源;而程序不能申請系統資源,不能被系統調度,也不能作爲獨立運行的單位,因此,它不佔用系統的運行資源。
線程:是進程中的一個單一的連續控制流程。一個進程可以擁有多個線程。線程又稱爲輕量級進程,它和進程一樣擁有獨立的執行控制,由操作系統負責調度,區別在於線程沒有獨立的存儲空間,而是和所屬進程中的其它線程共享一個存儲空間,這使得線程間的通信遠較進程簡單。
Java在語言級提供了對多線程程序設計的支持。
實現多線程程序的兩種方式:
a.從Thread類繼承
b.實現Runnable接口
(1)實現方式1從Thread類繼承
測試代碼如下:
- class MyThread extends Thread
- {
- MyThread(String name)
- {
- super(name);
- }
- public void run()
- {
- while(true)
- {
- System.out.println(getName());
- yield();//暫停線程運行
- }
- }
- }
- class MultiThread
- {
- public static void main(String[] args)
- {
- //從Thread類派生
- MyThread mt=new MyThread("Thread1");
- //mt.setDaemon(true);//標記爲後臺線程
- mt.setPriority(Thread.MAX_PRIORITY );//設置最高優先級
- mt.start();//啓動線程
- int index=0;
- //當僅有後臺線程運行時java虛擬機將退出
- while(true)
- {
- if(index++ == 100)
- break;//main方法退出
- System.out.println("main:"+Thread.currentThread().getName());
- }
- }
class MyThread extends Thread
{
MyThread(String name)
{
super(name);
}
public void run()
{
while(true)
{
System.out.println(getName());
yield();//暫停線程運行
}
}
}
class MultiThread
{
public static void main(String[] args)
{
//從Thread類派生
MyThread mt=new MyThread("Thread1");
//mt.setDaemon(true);//標記爲後臺線程
mt.setPriority(Thread.MAX_PRIORITY );//設置最高優先級
mt.start();//啓動線程
int index=0;
//當僅有後臺線程運行時java虛擬機將退出
while(true)
{
if(index++ == 100)
break;//main方法退出
System.out.println("main:"+Thread.currentThread().getName());
}
}
(2)實現方式2實現Runnable接口測試代碼如下:
//實現接口 允許繼承類並且實現接口 同一資源的訪問
- class MyThread implements Runnable
- {
- int index=0;//共享變量
- public void run()
- {
- while(true)
- {
- System.out.println(Thread.currentThread().getName()+index++);
- }
- }
- }
- class MultiThread
- {
- public static void main(String[] args)
- {
- MyThread mt=new MyThread( );
- new Thread(mt).start();//傳遞Runnable接口的實現類對象
- new Thread(mt).start();
- new Thread(mt).start();
- new Thread(mt).start();
- while(true)
- {
- System.out.println("main:"+Thread.currentThread().getName());
- }
- }
class MyThread implements Runnable
{
int index=0;//共享變量
public void run()
{
while(true)
{
System.out.println(Thread.currentThread().getName()+index++);
}
}
}
class MultiThread
{
public static void main(String[] args)
{
MyThread mt=new MyThread( );
new Thread(mt).start();//傳遞Runnable接口的實現類對象
new Thread(mt).start();
new Thread(mt).start();
new Thread(mt).start();
while(true)
{
System.out.println("main:"+Thread.currentThread().getName());
}
}
運行過程中如下圖所示:
測試代碼如下:
- //利用內部類繼承Thread
- class MyThread
- {
- int index=0;
- private class InnerThread extends Thread
- {
- public void run()
- {
- while(true)
- {
- System.out.println (Thread.currentThread().getName()+index++);
- }
- }
- }
- public Thread getThread()
- {
- return new InnerThread();
- }
- }
- class MultiThread
- {
- public static void main(String[] args)
- { MyThread mt=new MyThread();
- mt.getThread().start();
- mt.getThread().start();
- while(true)
- {
- System.out.println("main:"+Thread.currentThread().getName());
- }
- }
- }
//利用內部類繼承Thread
class MyThread
{
int index=0;
private class InnerThread extends Thread
{
public void run()
{
while(true)
{
System.out.println (Thread.currentThread().getName()+index++);
}
}
}
public Thread getThread()
{
return new InnerThread();
}
}
class MultiThread
{
public static void main(String[] args)
{ MyThread mt=new MyThread();
mt.getThread().start();
mt.getThread().start();
while(true)
{
System.out.println("main:"+Thread.currentThread().getName());
}
}
}
3.線程的同步同步的兩種方式:同步塊和同步方法
每一個對象都有一個監視器,或者叫做鎖。
同步方法利用的是this所代表的對象的鎖。靜態方法的同步利用的該類的Class對象的監視器。每個class也有一個鎖,是這個class所對應的Class對象的鎖。
(1)線程未同步時出錯:
測試代碼如下:
- class SellThread implements Runnable
- {
- int tickets=1000;
- Object ob=new Object();
- public void run()
- {
- while(true)
- {
- //不加鎖
- if(tickets>0)
- {
- try
- {
- Thread.sleep(5);
- }
- catch (Exception e)
- {
- System.out.println(e.toString());
- }
- System.out.println(Thread.currentThread().getName()+" Sell Tickets"+tickets);
- tickets--;
- }
- }
- class TicketsSystem
- {
- public static void main(String[] args)
- {
- SellThread st=new SellThread();
- new Thread(st).start();
- new Thread(st).start();
- }
- }
class SellThread implements Runnable
{
int tickets=1000;
Object ob=new Object();
public void run()
{
while(true)
{
//不加鎖
if(tickets>0)
{
try
{
Thread.sleep(5);
}
catch (Exception e)
{
System.out.println(e.toString());
}
System.out.println(Thread.currentThread().getName()+" Sell Tickets"+tickets);
tickets--;
}
}
class TicketsSystem
{
public static void main(String[] args)
{
SellThread st=new SellThread();
new Thread(st).start();
new Thread(st).start();
}
}
//運行結果Thread-0 Sell Tickets11
Thread-1 Sell Tickets10
Thread-0 Sell Tickets9
Thread-1 Sell Tickets8
Thread-0 Sell Tickets7
Thread-1 Sell Tickets6
Thread-0 Sell Tickets5
Thread-1 Sell Tickets4
Thread-0 Sell Tickets3
Thread-1 Sell Tickets2
Thread-0 Sell Tickets1
Thread-1 Sell Tickets0
(2)線程同步方法1--利用同步塊
測試代碼如下:
- class SellThread implements Runnable
- {
- int tickets=1000;
- Object ob=new Object();
- public void run()
- {
- while(true)
- { synchronized(ob)//同步塊 對Object對象加鎖
- {
- if(tickets>0)
- {
- try
- {
- Thread.sleep(5);
- }
- catch (Exception e)
- {
- System.out.println(e.toString());
- }
- System.out.println(Thread.currentThread().getName()+" Sell Tickets"+tickets);
- tickets--;
- }
- }//同步塊執行完畢 解鎖
- }
- class TicketsSystem
- {
- public static void main(String[] args)
- {
- SellThread st=new SellThread();
- new Thread(st).start();
- new Thread(st).start();
- }
- }
class SellThread implements Runnable
{
int tickets=1000;
Object ob=new Object();
public void run()
{
while(true)
{ synchronized(ob)//同步塊 對Object對象加鎖
{
if(tickets>0)
{
try
{
Thread.sleep(5);
}
catch (Exception e)
{
System.out.println(e.toString());
}
System.out.println(Thread.currentThread().getName()+" Sell Tickets"+tickets);
tickets--;
}
}//同步塊執行完畢 解鎖
}
class TicketsSystem
{
public static void main(String[] args)
{
SellThread st=new SellThread();
new Thread(st).start();
new Thread(st).start();
}
}
同步塊,運行結果如下圖所示:
測試代碼如下:
- class SellThread implements Runnable
- {
- int tickets=1000;
- Object ob=new Object();
- public void run()
- {
- while(true)
- {
- sell();//同步方法
- }
- }
- //synchronized關鍵字定義 同步方法 對this對象的監視器加鎖
- public synchronized void sell()
- {
- if(tickets>0)
- {
- try
- {
- Thread.sleep(10);
- }
- catch (Exception e)
- {
- System.out.println(e.toString());
- }
- System.out.println(Thread.currentThread().getName()+" Sell Tickets"+tickets);
- tickets--;
- }
- }//解鎖this對象
- }
- class TicketsSystem
- {
- public static void main(String[] args)
- {
- SellThread st=new SellThread();
- new Thread(st).start();
- new Thread(st).start();
- }
- }
class SellThread implements Runnable
{
int tickets=1000;
Object ob=new Object();
public void run()
{
while(true)
{
sell();//同步方法
}
}
//synchronized關鍵字定義 同步方法 對this對象的監視器加鎖
public synchronized void sell()
{
if(tickets>0)
{
try
{
Thread.sleep(10);
}
catch (Exception e)
{
System.out.println(e.toString());
}
System.out.println(Thread.currentThread().getName()+" Sell Tickets"+tickets);
tickets--;
}
}//解鎖this對象
}
class TicketsSystem
{
public static void main(String[] args)
{
SellThread st=new SellThread();
new Thread(st).start();
new Thread(st).start();
}
}
同步方法,運行結果如下圖所示:
驗證代碼如下:
- class SellThread implements Runnable
- {
- int tickets=500;//不同的數據可能線程的運行結果不一樣
- Object obj=new Object();
- boolean b=false;
- public void run()
- {
- if(b==false)
- {
- while(true)
- {
- sell();
- }
- }
- else
- {
- while(true)
- {
- synchronized(obj) //同步obj對象則出錯 同步this則正確
- {
- try
- {
- Thread.sleep(10);
- }
- catch (Exception e)
- {
- System.out.println(e.toString());
- }
- if(tickets>0)
- {
- System.out.println("Obj"+Thread.currentThread().getName()+" Sell Tickets"+tickets);
- tickets--;
- }
- }
- }
- }
- }
- //同步方法 對this對象的監視器加鎖
- public synchronized void sell()
- {
- if(tickets>0)
- {
- try
- {
- Thread.sleep(10);
- }
- catch (Exception e)
- {
- System.out.println(e.toString());
- }
- System.out.println("Sell"+Thread.currentThread().getName()+" Sell Tickets"+tickets);
- tickets--;
- }
- }//解鎖this對象
- }
class SellThread implements Runnable
{
int tickets=500;//不同的數據可能線程的運行結果不一樣
Object obj=new Object();
boolean b=false;
public void run()
{
if(b==false)
{
while(true)
{
sell();
}
}
else
{
while(true)
{
synchronized(obj) //同步obj對象則出錯 同步this則正確
{
try
{
Thread.sleep(10);
}
catch (Exception e)
{
System.out.println(e.toString());
}
if(tickets>0)
{
System.out.println("Obj"+Thread.currentThread().getName()+" Sell Tickets"+tickets);
tickets--;
}
}
}
}
}
//同步方法 對this對象的監視器加鎖
public synchronized void sell()
{
if(tickets>0)
{
try
{
Thread.sleep(10);
}
catch (Exception e)
{
System.out.println(e.toString());
}
System.out.println("Sell"+Thread.currentThread().getName()+" Sell Tickets"+tickets);
tickets--;
}
}//解鎖this對象
}
當一個調用sell方法,一個利用Object對象同步時,出錯,錯誤結果如下圖所示:
當一個調用sell方法,另一個利用this對象同步時,結果正確,如下圖所示:
死鎖測試代碼:
- //測試死鎖
- class SellThread implements Runnable
- {
- int tickets=500;
- Object obj=new Object();
- boolean b=false;
- public void run()
- {
- if(b)
- {
- while(true)
- sell();
- }
- else
- {
- while(true)
- {
- //先同步obj對象 然後同步this對象
- synchronized(obj)
- {
- try
- {
- Thread.sleep(10);
- }
- catch (Exception e)
- {
- System.out.println(e.toString());
- }
- synchronized(this)
- {
- if(tickets>0)
- {
- System.out.println("DeadLock"+Thread.currentThread().getName()+" Sell Tickets"+tickets);
- tickets--;
- }
- }
- }
- }
- }
- }
- //先同步this對象然後再同步obj對象
- public synchronized void sell()
- {
- synchronized(obj)
- {
- try
- {
- Thread.sleep(10);
- }
- catch (Exception e)
- {
- System.out.println(e.toString());
- }
- if(tickets>0)
- {
- System.out.println("DeadLock"+Thread.currentThread().getName()+" Sell Tickets"+tickets);
- tickets--;
- }
- }
- }//解鎖this對象
- }
- class TicketsSystem
- {
- public static void main(String[] args)
- {
- SellThread st=new SellThread();
- new Thread(st).start();
- try
- {
- Thread.sleep(10);
- }
- catch (Exception e)
- {
- System.out.println(e.toString());
- }
- st.b=true;
- new Thread(st).start();
- }
- }
//測試死鎖
class SellThread implements Runnable
{
int tickets=500;
Object obj=new Object();
boolean b=false;
public void run()
{
if(b)
{
while(true)
sell();
}
else
{
while(true)
{
//先同步obj對象 然後同步this對象
synchronized(obj)
{
try
{
Thread.sleep(10);
}
catch (Exception e)
{
System.out.println(e.toString());
}
synchronized(this)
{
if(tickets>0)
{
System.out.println("DeadLock"+Thread.currentThread().getName()+" Sell Tickets"+tickets);
tickets--;
}
}
}
}
}
}
//先同步this對象然後再同步obj對象
public synchronized void sell()
{
synchronized(obj)
{
try
{
Thread.sleep(10);
}
catch (Exception e)
{
System.out.println(e.toString());
}
if(tickets>0)
{
System.out.println("DeadLock"+Thread.currentThread().getName()+" Sell Tickets"+tickets);
tickets--;
}
}
}//解鎖this對象
}
class TicketsSystem
{
public static void main(String[] args)
{
SellThread st=new SellThread();
new Thread(st).start();
try
{
Thread.sleep(10);
}
catch (Exception e)
{
System.out.println(e.toString());
}
st.b=true;
new Thread(st).start();
}
}
//運行結果如下:DeadLockThread-0 Sell Tickets500
5.wait、notify、notifyAll
每一個對象除了有一個鎖之外,還有一個等待隊列(wait set),當一個對象剛創建的時候,它的等待隊列是空的。
我們應該在當前線程鎖住對象的鎖後,去調用該對象的wait方法。
當調用對象的notify方法時,將從該對象的等待隊列中刪除一個任意選擇的線程,這個線程將再次成爲可運行的線程。當調用對象的notifyAll方法時,將從該對象的等待隊列中刪除所有等待的線程,這些線程將成爲可運行的線程。
wait和notify主要用於producer-consumer這種關係中。(1)notify和wait方法需要在同步塊中執行否則出錯,錯誤信息如下:
Exception in thread "Thread-0" Exception in thread "Thread-1" java.lang.IllegalM
onitorStateException
at java.lang.Object.notify(Native Method)
at Queue.get(Test.java:81)
at Consumer.run(Test.java:40)
java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at Queue.put(Test.java:55)
at Producer.run(Test.java:23)
同時注意wait方法需要捕獲異常。
(2)消費者和生成者同步的模擬
測試代碼如下:
- class Test
- {
- public static void main(String[] args)
- {
- Queue q=new Queue();
- Producer p=new Producer(q);
- Consumer c=new Consumer(q);
- p.start();
- c.start();
- }
- }
- class Producer extends Thread
- {
- Queue q;
- Producer(Queue q)
- {
- this.q=q;
- }
- public void run()
- {
- for(int i=0;i<10;i++)
- {
- q.put(i);
- System.out.println("Producer put "+i);
- }
- }
- }
- class Consumer extends Thread
- {
- Queue q;
- Consumer(Queue q)
- {
- this.q=q;
- }
- public void run()
- {
- while(true)
- {
- System.out.println("Consumer get "+q.get());
- }
- }
- }
- class Queue
- {
- int value=-1;
- boolean bfull=false;
- //注意同步塊 wait和notify時必須對於同一個對象的隊列
- public synchronized void put(int i)
- {
- //爲空則放置數據
- if(!bfull)
- {
- value=i;
- bfull=true;
- notify();//通知等待的消費者
- }
- try
- {
- wait();
- }
- catch (Exception e)
- {
- System.out.println(e.toString());
- }
- }
- public synchronized int get()
- {
- //爲空則等待填充數據
- if(!bfull)
- {
- try
- {
- wait();
- }
- catch (Exception e)
- {
- System.out.println(e.toString());
- }
- }
- bfull=false;
- notify();//通知等待的生產者
- return value;
- }
- }
class Test
{
public static void main(String[] args)
{
Queue q=new Queue();
Producer p=new Producer(q);
Consumer c=new Consumer(q);
p.start();
c.start();
}
}
class Producer extends Thread
{
Queue q;
Producer(Queue q)
{
this.q=q;
}
public void run()
{
for(int i=0;i<10;i++)
{
q.put(i);
System.out.println("Producer put "+i);
}
}
}
class Consumer extends Thread
{
Queue q;
Consumer(Queue q)
{
this.q=q;
}
public void run()
{
while(true)
{
System.out.println("Consumer get "+q.get());
}
}
}
class Queue
{
int value=-1;
boolean bfull=false;
//注意同步塊 wait和notify時必須對於同一個對象的隊列
public synchronized void put(int i)
{
//爲空則放置數據
if(!bfull)
{
value=i;
bfull=true;
notify();//通知等待的消費者
}
try
{
wait();
}
catch (Exception e)
{
System.out.println(e.toString());
}
}
public synchronized int get()
{
//爲空則等待填充數據
if(!bfull)
{
try
{
wait();
}
catch (Exception e)
{
System.out.println(e.toString());
}
}
bfull=false;
notify();//通知等待的生產者
return value;
}
}
//運行結果(不知道爲什麼不是先打印Producer)Consumer get 0
Producer put 0
Consumer get 1
Producer put 1
Consumer get 2
Producer put 2
Consumer get 3
Producer put 3
Consumer get 4
Producer put 4
Consumer get 5
Producer put 5
Consumer get 6
Producer put 6
Consumer get 7
Producer put 7
Consumer get 8
Producer put 8
Consumer get 9
Producer put 9
6.線程終止
設置一個flag變量並結合interrupt()方法。
測試代碼如下:
- class TestThread
- {
- public static void main(String[] args)
- {
- Thread1 t1=new Thread1();
- t1.start();
- int index=0;
- while(true)
- {
- if(index++ == 500)
- {
- t1.stopThread();//調用後置停止運行標誌爲true
- t1.interrupt();//停止運行線程
- break;
- }
- System.out.println(Thread.currentThread().getName());
- }
- System.out.println("main exit!");
- }
- }
- class Thread1 extends Thread
- {
- private boolean bstop=false;
- public synchronized void run()
- {
- while(!bstop)
- {
- try
- {
- wait();//導致無法比較bstop 無法退出
- }
- catch (InterruptedException e)
- {
- //結合一個標誌,在interrupt函數執行時判斷標誌,退出程序
- if(bstop)
- return;
- e.printStackTrace();
- }
- System.out.println(getName());
- }
- }
- public void stopThread()
- {
- bstop=true;//置停止運行標誌爲true
- }
- }
class TestThread
{
public static void main(String[] args)
{
Thread1 t1=new Thread1();
t1.start();
int index=0;
while(true)
{
if(index++ == 500)
{
t1.stopThread();//調用後置停止運行標誌爲true
t1.interrupt();//停止運行線程
break;
}
System.out.println(Thread.currentThread().getName());
}
System.out.println("main exit!");
}
}
class Thread1 extends Thread
{
private boolean bstop=false;
public synchronized void run()
{
while(!bstop)
{
try
{
wait();//導致無法比較bstop 無法退出
}
catch (InterruptedException e)
{
//結合一個標誌,在interrupt函數執行時判斷標誌,退出程序
if(bstop)
return;
e.printStackTrace();
}
System.out.println(getName());
}
}
public void stopThread()
{
bstop=true;//置停止運行標誌爲true
}
}
//運行結果如下main
main
main
main
main
main
main
main
main
main exit!
請按任意鍵繼續. . .