線程相關知識

進程本質上是一個執行的程序。
每個進程都有自己獨立的一塊內存空間、一組系統資源。在進程概念中,每一個進程的內部數據和狀態都是完全獨立的。
線程與進程相似,是一段完成某個特定功能的代碼,是程序中單個順序的流控制,但與進程進程不同的是,同類的多個線程是共享同一塊內存空間和一組內存空間和一組系統資源的,而線程本身的數據通常只有微處理器的寄存器數據,以及一個供程序執行時使用的堆棧。
多線程是指在單個程序中可以同時運行多個不同的線程,執行不同的任務。多線程意味着一個程序的多行語句可以看上去幾乎在同一時間內同時運行。
要產生一個線程,有兩種方法:
1.需要從java.lang.Thread類派生一個新的線程類,重載它的run()方法。
2.實現Runnable接口,重載Runnable接口中的run()方法。
class NewThread extends Thread
{
 NewThread(){
  super("Thread Demo");
  System.out.println("New thread :"+getName());
 }
 
 public void run(){
  while(true){
   System.out.println(Thread.currentThread().getName()+"  is running");//靜態方法
  
  }
 }
}

class ThreadDemo{
 public static void main(String[] args){
  NewThread thd  = new NewThread();
  thd.start();
 
 }

}
=================================================================================================================
class NewThread implements Runnable{

 public void run(){
  for(int i = 10;i>0;i--){
   try{
    System.out.println("left time ;"+i);
    Thread.sleep(1000);
    
   }catch(InterruptedException e){
    System.out.println(e.getMessage());
   }
  }
  System.out.println("game is over,bye!");
 }

}


class ThreadDemo{
 public static void main(String [] args){
  NewThread newthread = new NewThread();
  Thread thd = new Thread(newthread,"Thread Demo");
  thd.start();
 }

}

由於操作系統在調度線程的時候並不是按順序進行的,而是將時間片輪流分給每一個線程,具體每一次分給哪個線程也是不確定的,但可以保證在很短的時間內,每一個線程都有機會被執行的機會。

火車票問題,用線程的方式來解決

class MutliThread implements Runnable{
 private int ticket =100;
 
 public void run(){
  while(ticket>0){
   System.out.println(ticket -- +" is saled by "+Thread.currentThread().getName());
  
  }
  
 }

}


class MutliThreadDemo{
 public static void main(String [] args){
 
  MutliThread m = new MutliThread();
  Thread t1 = new Thread(m,"window 1");
  Thread t2 = new Thread(m,"window 2");
  Thread t3 = new Thread(m,"window 3");
  t1.start();
  t2.start();
  t3.start();
 }

}

Java中,線程的優先級是介於Thread.MIN_PRIORITY到Thread.MAX_PRIORITY這兩個常量之間的某個整數數值(1-10)。默認情況下,線程的優先級都是5,在java中用NORM_PRIORITY來表示。其中,MIN_PRIORITY,MAX_PRIORITY,NORM_PRIORIYT均是Thread類的靜態整型常量。

當利用某一線程又創建了一個新線程對象時,這個新線程將擁有與創建它的線程一樣的優先級。

線程的生命週期
1.創建狀態  當一個線程被實例化後,它就處於創建狀態,直到調用start()方法。當一個線程處於創建狀態時,它僅僅是一個空的線程對象,系統不爲它分配資源。在這個狀態下,線程還不是活的。
Thread myThread = new MyThreadClass();
 
2.可運行狀態 對於處於創建狀態的線程來說,只要對其調用start()方法,就可以使該線程進入可運行狀態。當一個線程處於可運行狀態時,系統爲這個線程分配它所需要的系統資源,然後安排其運行並調用線程的run()方法。此時的線程具備了所有能夠運行的條件,但是,此狀態的線程並不一定馬上就被執行。這是因爲目前所使用的計算機大多都是單處理器的,因此,要想在同一時刻運行所有的處於運行狀態的線程是不可能的。
myThread.start();

3.不可運行狀態
可以認爲,在下面列出的條件之一發生時,線程進入不可運行狀態。
(1)調用了sleep()方法;
(2)爲等候一個條件變量,線程調用了wait()方法;
(3)輸入輸出流中線程被阻塞。
不可運行狀態也可以稱爲阻塞狀態(Blocked)。如:sleep的時間到達、得到條件變量之後使用了notify()方法或者notifyAll()方法喚醒了waiting中的一個或所有線程、獲得了需要的I/O資源等。

4.消亡狀態
一般來講,線程的run()方法執行完畢時,該線程就被視爲進入了消亡狀態。一個處於消亡狀態的線程不能再進入其他狀態,即使對它調用start()方法也無濟於事。可以通過兩種方法使線程進入消亡狀態:自然撤銷(線程執行完)或是強行中止。


等待一個線程執行結束後再運行另一個線程,有兩種方法:
方法一:
class NewThread implements Runnable{
 
//省略
}

class ThreadTestDemo{
 public static void main(String []args){
 
  NewThread n = new NewThread();
  
  Thread t1 = new Thread(n,"thread1");
  Thread t2 = new Thread(n,"thread2");
  t1.start();
  while(t1.isAlive()){
   try{
    Thread.sleep(100);//讓主線程休眠100毫秒,程序不往下執行。
   }catche(InterruptedException e){
    e.printStackTrace();
   }
  }
  t2.start();
 }

}
===================================================================================================================
方法二:

class NewThread implements Runnable{
 
//省略
}

class ThreadTestDemo2{

 public static void main(String []args){
  NewThread n = new NewThread();
  
  Thread t1 = new Thread(n,"thread1");
  Thread t2 = new Thread(n,"thread2");
  
  t1.start();
  try{
   t1.join();//當前線程等待線程t1執行完後再繼續往下執行。
  }catch(InterruptedException e ){
   e.printStackTrace();
  }
  t2.start();
 }
}

線程中斷:(用戶線程在調用interrupt()方法後,並沒有被中斷,而是繼續執行,直到人爲地中止。m1.interrupt()語句只有當線程發生阻塞時纔有效。它的作用就是拋出一個InterruptedException類的異常對象,是try...catch語句捕獲異常,並對其進行處理。)
class MyThread extends Thread{
 boolean stop = false;
 
 public void run(){
  while(!stop){
   System.out.println(getName()+" is running");
   try{
    sleep(1000);
   }catch(InterruptedException e ){
    e.printStackTrace();
   }
  }
  System.out.println("Thread is exiting...");
 }
}

class InterruptThreadDemo{
 public static void main(String [] args){
 
  MyThread m = new MyThread();
  System.out.println("Starting thread ...");
  m.start();
  Thread.sleep(3000);
  System.out.println("Interrupt thread...");
  m.stop = true;//修改共享變量
  Thread.sleep(3000);//主線程休眠以觀察線程中斷後的情況
  System.out.println("Stopping application ...");
 }
}


同步:
情況一:使用同步代碼塊

class SaleTickets implements Runnable{
 private String ticketNo = "100750";//車票編號
 private int ticket = 1;//共享私有成員,編號爲100750的車票數量爲1
 public void run(){
 
  System.out.println(Thread.CurrentThread().getName() + " is saling Thicket"+ticketNo);//
  //下面同步代碼塊中的代碼爲關鍵代碼,用synchronized關鍵字來標識
  synchronized(this){
   if(ticket>0){
    try{
     Thread.sleep((int)(Matn.random()*1000));
    }catch(InterruptedException e){
     e.printStackTrace();
    }
    ticket = ticket - 1;
    System.out.println("ticket is saled by "+ Thread.currentThread().getName()+",amount is :"ticket);
   }
   else{
    System.out.println("Sorry "+Thread.currentThread().getName()+", Ticket" +ticketNo +"is saled");
   }
  }
 }
}

class SynchronizedDemo{
 public static void main(String [] args){
  SaleTicket m = new SaleTicket();
  Thread t1 = Thread(m,"System1");
  Thread t2 = Thread(m,"System2");
  t1.start();
  t2.start();
 }
}


情況二:使用同步方法

class SaleTickets implements Runnable{
 private String ticketNo = "100750";//車票編號
 private int ticket = 1;//共享私有成員,編號爲100750的車票數量爲1
 public void run(){
 
  System.out.println(Thread.CurrentThread().getName() + " is saling Thicket"+ticketNo);//
  //下面同步代碼塊中的代碼爲關鍵代碼,用synchronized關鍵字來標識
  sale();
 }
 public synchronized void sale(){ //同步方法中的代碼爲關鍵代碼
 
    if(ticket>0){
    try{
     Thread.sleep((int)(Matn.random()*1000));
    }catch(InterruptedException e){
     e.printStackTrace();
    }
    ticket = ticket - 1;
    System.out.println("ticket is saled by "+ Thread.currentThread().getName()+",amount is :"ticket);
   }
   else{
    System.out.println("Sorry "+Thread.currentThread().getName()+", Ticket" +ticketNo +"is saled");
   }
 }
}

 

class SynchronizedDemo{
 public static void main(String [] args){
  SaleTicket m = new SaleTicket();
  Thread t1 = Thread(m,"System1");
  Thread t2 = Thread(m,"System2");
  t1.start();
  t2.start();
 }
}

這兩種方法的區別:
簡單地說,用synchronized關鍵字修飾的方法不能被繼承。或者說,如果父類的某個方法使用了synchronized關鍵字修飾,那麼在其子類中該方法的重載方法是不會繼承其同步特徵的。如果需要在子類中實現同步,應該重新使用synchronized關鍵字來修飾。

注意:在多線程的程序中,雖然可以使用synchronized關鍵字來修飾需要同步的方法,但是並不是每一個方法都可以被其修飾的。比如,不要同步一個線程對象的run()方法,因爲每一個線程運行都是從run()方法開始的。在需要同步的多線程程序中,所有線程共享這一方法,由於該方法又被synchronized關鍵字所修飾,因此一個時間內只能有一個線程能夠執行run()方法,結果所有線程都必須等待前一個線程結束後才能執行。

死鎖問題:即由於兩個或多個線程都無法得到相應的鎖二造成的兩個線程都等待的現象。這種現象主要是因爲相互嵌套synchronized代碼段而造成的。


共享池解決生產者和消費者問題

class SyncStack{

 private int index = 0;
 private char[] buffer = new char[5];
 
 public synchronized void push(char c){
 
  if(index == buffer.length){
   try{
    this.wait();
   }catch(InterruptedException e ){
    e.printStackTrace();
   }
  }
  
  buffer[index] = c;
  index++;
  this.notify();
 }

 public synchronized char pop(){
  if(index == 0){
   try{
    this.wait();
   }catch(InterruptedException e ){
    e.printStackTrace();
   }
  }
  this.notify();
  index --;
  return buffer[index];
 }
}

class Producer implements Runner{
 SyncStack s;
 public Producer(SyncStack s){
  this.s = s;
 }
 
 public void run(){
  char ch;
  for(int i = 0;i<5;i++){
   try{
    Thread.sleep((int)(Math.random()*1000));
   
   }catch(InterruptedException e){
    e.printStackTrace();
   }
   ch = (char)(Math.random()*26+A);
   s.push(ch);
   System.out.println("Push" + ch +"in Stack");
  }
 }
}


class Consumer implements Runnable{
 SyncStack s ;
 
 public Consumer(SyncStack s){
  this.s = s;
 }
 
 public void run(){
  char ch;
  
  for(int i=0;i<5;i++){
   try{
    Thread.sleep((int)(Math.random()*3000));
   }catch(InterruptedException e){
    e.printStackTrace();
   }
   ch =s.pop();
   System.out.println("Pop" + ch +"  from stack");
  }
 }
}

public class Communication{
 public static void main(String[] args){
  SyncStack stack = new SyncStack();
  Thread t1 = new Thread(new Producer(stack));
  Thread t2 = new Thread(new Producer(stack));
  t1.start();
  t2.start();
 }

}

發佈了48 篇原創文章 · 獲贊 1 · 訪問量 1784
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章