瞭解進程和線程
1在多任務系統中,每個獨立執行的程序成爲進程,也就是“正在進行的程序”。我們現在使用的操作
系統一般都是多任務的,即能夠同時執行多個應用程序,實際情況是,操作系統負責對CPU等設備的資源
進行分配和管理,雖然這些設備某一時刻只能做一件事情,但是以非常小的時間間隔交替執行多個程序,
就可以給人以執行多個程序的感覺。
2一個進程又可以包含一個或多個線程,一個線程就是一個程序內部的一條執行線索,如果要一個程序
中實現多段代碼同時交替運行,就需要產生多個線程,並指定每個線程上所要運行的程序代碼段,這就是
多線程。
用Thread類創建線程
1 要將一段代碼在一個新的線程上運行,該代碼應該在一個類的run函數中,並且run函數所在的類是
Thread類的子類。倒過來看:我們要實現多線程,必須編寫一個繼承了Thread類的子類,子類覆蓋了
Thread的run()函數,在子類的函數中調用想在新線程上運行的程序代碼。
2 啓動一個新的線程我們不是直接調用Thread的子類的run()方法,而是調用Thread子類對象的start方
法,start()方法將產生一個新的線程,並在該線程上運行該Thread類對象中的run()方法,根據面向對象
的運行時的多態性,在該線程上實際運行的是Thread子類對象的run()方法。
3由於線程的代碼段在run方法中,那麼該方法執行完成以後線程也就相應的結束了,因而我們可以通過
控制run方法中的循環條件來控制線程的結束。
後臺線程與聯合線程
1如果我們對某個線程在啓動(調用start())之前調用了setDaemon(true)方法,這個線程就變成了後臺
線程。 (2)例子
2對java程序來說,只要還有一個前臺線程在運行,這個進程就不會結束,如果一個進程中只有後臺線程
運行,這個進程就會結束。(2)例子
3 PP.join()的作用是把pp所對應的線程合併到調用PP.join();語句的線程中。(3)例子
4 實現多線程的另一個方法 創建一個Implements Runnable接口的類,此時線程中所運行的是Runnable
的run方法 (4)例子
(2) 例子:
class ThreadTest extends Thread{
public void run()
{
while(true)
{
System.out.println("run()"+Thread.currentThread().getName());
}
}
public static void main(String[] args) {
Thread tt=new ThreadTest();
tt.setDaemon(true);
tt.start();
/*while (true)
{
System.out.println("main()"+Thread.currentThread().getName());
} */}}
(3)例子
package Hello;
class ThreadTest extends Thread{
public void run(){
while(true){
System.out.println("run()"+Thread.currentThread().getName());
} }
public static void main(String[] args) {
Thread tt=new ThreadTest();
tt.start();
int count=0;
while (true)
{
if(count++ == 100) { //運行100次後合併線程10秒
try {
tt.join(10000);
} catch (Exception e) {
e.printStackTrace();
} }
System.out.println("main()"+Thread.currentThread().getName());
} } }
(4)例子
class ThreadTest implements Runnable//extends Thread{
{ public void run(){
while(true){
System.out.println("run()"+Thread.currentThread().getName());
} }
public static void main(String[] args) {
Thread tt=new Thread(new ThreadTest());
//tt.setDaemon(true);
tt.start();
int count=0;
while (true)
{
if(count++ == 100) {
try {
tt.join(10000);
} catch (Exception e) {
e.printStackTrace();
} }
System.out.println("main()"+Thread.currentThread().getName());
} } }
使用Runnable 接口創建多線程
1 適合多個相同程序代碼的線程去處理同一資源的情況,把虛擬CPU(線程) 同程序的代碼,數據有效分
離,較好的體現了面向對象的設計思想。
2 可以避免由於java的單繼承特性帶來的侷限。我們將已經繼承了一個類的子類放入多線程,由於不能
有兩個父類,就不能繼承Thread,那麼這個類就只能實現Runnable接口。
3 當線程被構造時,需要的代碼和數據通過一個對象作爲 構造函數的實參傳遞進去,這個對象就是實現
了Runnable接口的類的實例。
4 事實上,幾乎所有的多線程應用都可用Runnable接口方式。
5 例子(5)中 run方法可能在一個線程執行一半時,cpu被分配到了另一個線程,導致同一個票多次售
出。這是我們需要考慮到多線程的同步性。synchronized(str)同步代碼塊,我們把需要同步的代碼放在
代碼塊中。synchronized後必須傳遞一個對象(這個對象可以是任意的,但是對象的創建必須在run方法
之外),當線程運行到代碼塊時,會查看對象的標誌位(鎖旗標)如果爲1則進入代碼塊,並把標誌位改
爲0,直到執行完 釋放鎖旗標(標誌位變爲1)。
6 除了同步代碼塊 我們還可以使用同步函數(6)例子
7如何讓 同步代碼塊和同步函數同步呢 (7)例子
例子 編寫一個程序實現了四個窗口同時賣100張票。
(5) 同步代碼塊
public class RunnableTest implements Runnable {
String str=new String("");
int ticket=100;
public void run(){
synchronized(str)
{ if(ticket>0) //同步代碼塊
System.out.println(Thread.currentThread().getName()+
"is saling ticket "+ ticket--);}}
public static void main(String[] args) {
RunnableTest tt=new RunnableTest();
while(true){
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start(); }}}
(6)同步函數
public class RunnableTest implements Runnable
{ int ticket=100;
public void run(){
while(true){sale();}
}
public synchronized void sale() {
if(ticket>0)
{System.out.println(Thread.currentThread().getName()+"is saling ticket "+ ticket--);}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
RunnableTest tt=new RunnableTest();
while(true){
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start(); }}}
(7)代碼塊和函數同步
public class RunnableTest implements Runnable {
int ticket = 100;
String str = new String("");
public void run() {
if (str.equals("method")) {
while (true) {sale();}
} else {while (true) {synchronized (this)// 同步代碼塊
{if (ticket > 0) {
System.out.println(Thread.currentThread().getName()+ "is saling ticket " + ticket--);
}}}}}
public synchronized void sale() {
if (ticket > 0) {
System.out.print("sale()");
System.out.println(Thread.currentThread().getName()
+ "is saling ticket " + ticket--);}}
public static void main(String[] args) {
RunnableTest tt = new RunnableTest();
new Thread(tt).start();
tt.str = new String("method");
new Thread(tt).start();}}
** 同步函數 是以this作爲鎖旗標,所有隻要把同步代碼塊 synchronized(this) 的對象設爲this 就
能實現它們的同步。
線程間的通信
1 wait: 告訴當前線程放棄監視器並進入睡眠狀態直到其它線程進入同一監視器並調用notify爲止
2 notofy: 喚醒同一對象監視器中調用wait的第一個線程。
3 notifyAll: 喚醒同一對象監視器中調用wait的所有線程,具有最高優先級的線程首先被喚醒並執行。
public class Q {
private String name="unknown";
private String sex="unknown";
boolean inFull=false;
public synchronized void put(String name,String sex)
{
if(inFull){
try {
wait();
} catch (Exception e) {
e.printStackTrace();
} }
this.name=name;
this.sex=sex;
inFull=true;
notify();
}
public synchronized void get()
{
if(!inFull)
{
try {
wait();
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.print(name);
System.out.println(":"+sex);
inFull=false;
notify(); }}
public class Producer implements Runnable {
Q q;
public Producer(Q q)
{
this.q=q;
}
public void run() {
int i=1;
while (true) {
if(i==1)
{
q.put("zhangsan", "boy");
}
else
{
q.put("wangwu", "girl");
}}}}
public class Consumer implements Runnable {
Q q;
public Consumer(Q q){
this.q=q;
}
public void run() {
// TODO Auto-generated method stub
while(true)
{
q.get(); } }}
public class ThreadConmunation {
public static void main(String[] args) {
Q q=new Q();
new Thread(new Producer(q)).start();
new Thread(new Consumer(q)).start();
}