欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳談java線程與線程、進(jìn)程與進(jìn)程間通信

 更新時(shí)間:2017年04月10日 10:51:29   投稿:jingxian  
下面小編就為大家?guī)硪黄斦刯ava線程與線程、進(jìn)程與進(jìn)程間通信。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

線程與線程間通信

一、基本概念以及線程與進(jìn)程之間的區(qū)別聯(lián)系:

關(guān)于進(jìn)程和線程,首先從定義上理解就有所不同

1、進(jìn)程是什么?

是具有一定獨(dú)立功能的程序、它是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位,重點(diǎn)在系統(tǒng)調(diào)度和單獨(dú)的單位,也就是說進(jìn)程是可以獨(dú) 立運(yùn)行的一段程序。

2、線程又是什么?

線程進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,他是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位,線程自己基本上不擁有系統(tǒng)資源。

在運(yùn)行時(shí),只是暫用一些計(jì)數(shù)器、寄存器和棧 。

他們之間的關(guān)系

1、一個(gè)線程只能屬于一個(gè)進(jìn)程,而一個(gè)進(jìn)程可以有多個(gè)線程,但至少有一個(gè)線程(通常說的主線程)。

2、資源分配給進(jìn)程,同一進(jìn)程的所有線程共享該進(jìn)程的所有資源。

3、線程在執(zhí)行過程中,需要協(xié)作同步。不同進(jìn)程的線程間要利用消息通信的辦法實(shí)現(xiàn)同步。

4、處理機(jī)分給線程,即真正在處理機(jī)上運(yùn)行的是線程。

5、線程是指進(jìn)程內(nèi)的一個(gè)執(zhí)行單元,也是進(jìn)程內(nèi)的可調(diào)度實(shí)體。

從三個(gè)角度來剖析二者之間的區(qū)別

1、調(diào)度:線程作為調(diào)度和分配的基本單位,進(jìn)程作為擁有資源的基本單位。

2、并發(fā)性:不僅進(jìn)程之間可以并發(fā)執(zhí)行,同一個(gè)進(jìn)程的多個(gè)線程之間也可以并發(fā)執(zhí)行。

3、擁有資源:進(jìn)程是擁有資源的一個(gè)獨(dú)立單位,線程不擁有系統(tǒng)資源,但可以訪問隸屬于進(jìn)程的資源。.

二、多線程間通信方式:

1、共享變量

2、wait/notify機(jī)制

3、Lock/Condition機(jī)制

4、管道

三、共享變量

線程間發(fā)送信號(hào)的一個(gè)簡單方式是在共享對(duì)象的變量里設(shè)置信號(hào)值。線程A在一個(gè)同步塊里設(shè)置boolean型成員變量hasDataToProcess為true,線程B也在同步塊里讀取hasDataToProcess這個(gè)成員變量。這個(gè)簡單的例子使用了一個(gè)持有信號(hào)的對(duì)象,并提供了set和check方法:


public class MySignal{

 protected boolean hasDataToProcess = false;

 public synchronized boolean hasDataToProcess(){
  return this.hasDataToProcess;
 }

 public synchronized void setHasDataToProcess(boolean hasData){
  this.hasDataToProcess = hasData;
 }

}

線程A和B必須獲得指向一個(gè)MySignal共享實(shí)例的引用,以便進(jìn)行通信。如果它們持有的引用指向不同的MySingal實(shí)例,那么彼此將不能檢測(cè)到對(duì)方的信號(hào)。需要處理的數(shù)據(jù)可以存放在一個(gè)共享緩存區(qū)里,它和MySignal實(shí)例是分開存放的。

四、wait()/notify機(jī)制

為了實(shí)現(xiàn)線程通信,我們可以使用Object類提供的wait()、notify()、notifyAll()三個(gè)方法。調(diào)用wait()方法會(huì)釋放對(duì)該同步監(jiān)視器的鎖定。這三個(gè)方法必須由同步監(jiān)視器對(duì)象來調(diào)用,這可分成兩種情況:

•對(duì)于使用synchronized修飾的同步方法,因?yàn)樵擃惖哪J(rèn)實(shí)例是(this)就是同步監(jiān)視器,所以可以直接調(diào)用這三使用個(gè)方法。

•對(duì)于synchronized修飾的同步代碼塊,同步監(jiān)視器是synchronized括號(hào)里的對(duì)象,所以必須使用該對(duì)象調(diào)用這三個(gè)方法。

假設(shè)系統(tǒng)中有兩條線程,這兩條線程分別代表取錢者和存錢者。現(xiàn)在系統(tǒng)有一種特殊的要求,系統(tǒng)要求存款者和取錢者不斷的實(shí)現(xiàn)存款和取錢動(dòng)作,而且要求每當(dāng)存款者將錢存入指定賬戶后,取錢者立即將錢取走.不允許存款者兩次存錢,也不允許取錢者兩次取錢。

我們通過設(shè)置一個(gè)旗標(biāo)來標(biāo)識(shí)賬戶中是否已有存款,有就為true,沒有就標(biāo)為false。具體代碼如下:

首先我們定義一個(gè)Account類,這個(gè)類中有取錢和存錢的兩個(gè)方法,由于這兩個(gè)方法可能需要并發(fā)的執(zhí)行取錢、存錢操作,所有將這兩個(gè)方法都修改為同步方法.(使用synchronized關(guān)鍵字)。

public class Account { 
  private String accountNo; 
  private double balance; 
  //標(biāo)識(shí)賬戶中是否有存款的旗標(biāo) 
  private boolean flag=false; 
   
  public Account() { 
    super(); 
  } 
 
  public Account(String accountNo, double balance) { 
    super(); 
    this.accountNo = accountNo; 
    this.balance = balance; 
  }  
   
  public synchronized void draw (double drawAmount){ 
     
    try { 
       if(!flag){ 
       this.wait(); 
       }else { 
         //取錢 
         System.out.println(Thread.currentThread().getName()+" 取錢:"+drawAmount); 
         balance=balance-drawAmount; 
         System.out.println("余額 : "+balance); 
         //將標(biāo)識(shí)賬戶是否已有存款的標(biāo)志設(shè)為false 
         flag=false; 
         //喚醒其它線程 
         this.notifyAll();     
       } 
      } catch (Exception e) { 
        e.printStackTrace(); 
    } 
  } 
   
   
  public synchronized void deposit(double depositAmount){ 
   try { 
       if(flag){ 
        this.wait(); 
       } 
       else{ 
         System.out.println(Thread.currentThread().getName()+"存錢"+depositAmount); 
         balance=balance+depositAmount; 
         System.out.println("賬戶余額為:"+balance); 
         flag=true; 
         //喚醒其它線程 
         this.notifyAll(); 
       } 
    } catch (Exception e) { 
      // TODO: handle exception 
      e.printStackTrace(); 
    } 
  } 
 
} 

接下來創(chuàng)建兩個(gè)線程類,分別為取錢和存錢線程!

取錢線程類:

public class DrawThread implements Runnable { 
 
  private Account account; 
  private double drawAmount; 
   
   
  public DrawThread(Account account, double drawAmount) { 
    super(); 
    this.account = account; 
    this.drawAmount = drawAmount; 
  } 
 
  public void run() { 
    for(int i=0;i<100;i++){ 
     account.draw(drawAmount);   
    } 
  } 
} 

存錢線程類:

public class depositThread implements Runnable{ 
  private Account account; 
  private double depositAmount; 
    
  public depositThread(Account account, double depositAmount) { 
    super(); 
    this.account = account; 
    this.depositAmount = depositAmount; 
  } 
 
 
  public void run() { 
  for(int i=0;i<100;i++){ 
     account.deposit(depositAmount); 
   } 
  } 
 
} 

最后我們測(cè)試一下這個(gè)取錢和存錢的操作

public class TestDraw { 
 
  public static void main(String[] args) { 
    //創(chuàng)建一個(gè)賬戶 
    Account account=new Account(); 
    new Thread(new DrawThread(account, 800),"取錢者").start(); 
    new Thread(new depositThread(account, 800),"存款者甲").start(); 
    new Thread(new depositThread(account, 800),"存款者乙").start(); 
    new Thread(new depositThread(account, 800),"存款者丙").start(); 
 
  } 
 
} 

大致的輸出結(jié)果:

存款者甲存錢800.0 
賬戶余額為:800.0 
取錢者 取錢:800.0 
余額 : 0.0 
存款者丙存錢800.0 
賬戶余額為:800.0 
取錢者 取錢:800.0 
余額 : 0.0 
存款者甲存錢800.0 
賬戶余額為:800.0 
取錢者 取錢:800.0 
余額 : 0.0 
存款者丙存錢800.0 
賬戶余額為:800.0 
取錢者 取錢:800.0 
余額 : 0.0 
存款者甲存錢800.0 
賬戶余額為:800.0 
取錢者 取錢:800.0 
余額 : 0.0 
存款者丙存錢800.0 
賬戶余額為:800.0 
取錢者 取錢:800.0 
余額 : 0.0 
存款者甲存錢800.0 
賬戶余額為:800.0 
取錢者 取錢:800.0 
余額 : 0.0 
存款者丙存錢800.0 
賬戶余額為:800.0 
取錢者 取錢:800.0 
余額 : 0.0 
存款者甲存錢800.0 
賬戶余額為:800.0 
取錢者 取錢:800.0 
余額 : 0.0 

五、Lock/Condition機(jī)制

如何程序不使用synchronized關(guān)鍵字來保持同步,而是直接適用Lock對(duì)像來保持同步,則系統(tǒng)中不存在隱式的同步監(jiān)視器對(duì)象,也就不能使用wait()、notify()、notifyAll()來協(xié)調(diào)線程的運(yùn)行.

當(dāng)使用LOCK對(duì)象保持同步時(shí),JAVA為我們提供了Condition類來協(xié)調(diào)線程的運(yùn)行。關(guān)于Condition類,JDK文檔里進(jìn)行了詳細(xì)的解釋.,再次就不啰嗦了。

我們就拿Account類進(jìn)行稍微的修改 一下吧!

import java.util.concurrent.locks.Condition; 
import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 
 
public class Account { 
   
  //顯示定義Lock對(duì)象 
  private final Lock lock=new ReentrantLock(); 
  //獲得指定Lock對(duì)象對(duì)應(yīng)的條件變量 
  private final Condition con=lock.newCondition();   
 
  private String accountNo; 
  private double balance; 
  //標(biāo)識(shí)賬戶中是否有存款的旗標(biāo) 
  private boolean flag=false; 
   
  public Account() { 
    super(); 
  } 
 
  public Account(String accountNo, double balance) { 
    super(); 
    this.accountNo = accountNo; 
    this.balance = balance; 
  }  
   
  public void draw (double drawAmount){ 
     
    //加鎖 
    lock.lock(); 
    try { 
       if(!flag){ 
//      this.wait(); 
       con.await(); 
       }else { 
         //取錢 
         System.out.println(Thread.currentThread().getName()+" 取錢:"+drawAmount); 
         balance=balance-drawAmount; 
         System.out.println("余額 : "+balance); 
         //將標(biāo)識(shí)賬戶是否已有存款的標(biāo)志設(shè)為false 
         flag=false; 
         //喚醒其它線程 
//        this.notifyAll();  
         con.signalAll(); 
       } 
      } catch (Exception e) { 
        e.printStackTrace(); 
    } 
      finally{ 
        lock.unlock(); 
      } 
  } 
   
   
  public void deposit(double depositAmount){ 
    //加鎖 
    lock.lock(); 
    try { 
       if(flag){ 
//       this.wait(); 
         con.await(); 
       } 
       else{ 
         System.out.println(Thread.currentThread().getName()+"存錢"+depositAmount); 
         balance=balance+depositAmount; 
         System.out.println("賬戶余額為:"+balance); 
         flag=true; 
         //喚醒其它線程 
//        this.notifyAll(); 
         con.signalAll(); 
       } 
    } catch (Exception e) { 
      // TODO: handle exception 
      e.printStackTrace(); 
    }finally{ 
      lock.unlock(); 
    } 
  } 
 
} 

輸出結(jié)果和上面是一樣的! 只不過這里 顯示的使用Lock對(duì)像來充當(dāng)同步監(jiān)視器,使用Condition對(duì)象來暫停指定線程,喚醒指定線程!

六、管道

管道流是JAVA中線程通訊的常用方式之一,基本流程如下:

1)創(chuàng)建管道輸出流PipedOutputStream pos和管道輸入流PipedInputStream pis

2)將pos和pis匹配,pos.connect(pis);

3)將pos賦給信息輸入線程,pis賦給信息獲取線程,就可以實(shí)現(xiàn)線程間的通訊了

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class testPipeConnection {

  public static void main(String[] args) {
    /**
     * 創(chuàng)建管道輸出流
     */
    PipedOutputStream pos = new PipedOutputStream();
    /**
     * 創(chuàng)建管道輸入流
     */
    PipedInputStream pis = new PipedInputStream();
    try {
      /**
       * 將管道輸入流與輸出流連接 此過程也可通過重載的構(gòu)造函數(shù)來實(shí)現(xiàn)
       */
      pos.connect(pis);
    } catch (IOException e) {
      e.printStackTrace();
    }
    /**
     * 創(chuàng)建生產(chǎn)者線程
     */
    Producer p = new Producer(pos);
    /**
     * 創(chuàng)建消費(fèi)者線程
     */
    Consumer1 c1 = new Consumer1(pis);
    /**
     * 啟動(dòng)線程
     */
    p.start();
    c1.start();
  }
}

/**
 * 生產(chǎn)者線程(與一個(gè)管道輸入流相關(guān)聯(lián))
 * 
 */
class Producer extends Thread {
  private PipedOutputStream pos;

  public Producer(PipedOutputStream pos) {
    this.pos = pos;
  }

  public void run() {
    int i = 0;
    try {
      while(true)
      {
      this.sleep(3000);
      pos.write(i);
      i++;
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

/**
 * 消費(fèi)者線程(與一個(gè)管道輸入流相關(guān)聯(lián))
 * 
 */
class Consumer1 extends Thread {
  private PipedInputStream pis;

  public Consumer1(PipedInputStream pis) {
    this.pis = pis;
  }

  public void run() {
    try {
      while(true)
      {
      System.out.println("consumer1:"+pis.read());
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

程序啟動(dòng)后,就可以看到producer線程往consumer1線程發(fā)送數(shù)據(jù)

consumer1:0
consumer1:1
consumer1:2
consumer1:3
......

管道流雖然使用起來方便,但是也有一些缺點(diǎn)

1)管道流只能在兩個(gè)線程之間傳遞數(shù)據(jù)

線程consumer1和consumer2同時(shí)從pis中read數(shù)據(jù),當(dāng)線程producer往管道流中寫入一段數(shù)據(jù)后,每一個(gè)時(shí)刻只有一個(gè)線程能獲取到數(shù)據(jù),并不是兩個(gè)線程都能獲取到producer發(fā)送來的數(shù)據(jù),因此一個(gè)管道流只能用于兩個(gè)線程間的通訊。不僅僅是管道流,其他IO方式都是一對(duì)一傳輸。

2)管道流只能實(shí)現(xiàn)單向發(fā)送,如果要兩個(gè)線程之間互通訊,則需要兩個(gè)管道流

可以看到上面的例子中,線程producer通過管道流向線程consumer發(fā)送數(shù)據(jù),如果線程consumer想給線程producer發(fā)送數(shù)據(jù),則需要新建另一個(gè)管道流pos1和pis1,將pos1賦給consumer1,將pis1賦給producer,具體例子本文不再多說。

II.進(jìn)程與進(jìn)程間通信

一、進(jìn)程間通信方式

(1)管道(Pipe):管道可用于具有親緣關(guān)系進(jìn)程間的通信,允許一個(gè)進(jìn)程和另一個(gè)與它有共同祖先的進(jìn)程之間進(jìn)行通信。

(2)命名管道(named pipe):命名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關(guān) 系 進(jìn)程間的通信。命名管道在文件系統(tǒng)中有對(duì)應(yīng)的文件名。命名管道通過命令mkfifo或系統(tǒng)調(diào)用mkfifo來創(chuàng)建。

(3)信號(hào)(Signal):信號(hào)是比較復(fù)雜的通信方式,用于通知接受進(jìn)程有某種事件發(fā)生,除了用于進(jìn)程間通信外,進(jìn)程還可以發(fā)送 信號(hào)給進(jìn)程本身;linux除了支持Unix早期信號(hào)語義函數(shù)sigal外,還支持語義符合Posix.1標(biāo)準(zhǔn)的信號(hào)函數(shù)sigaction(實(shí)際上,該函數(shù)是基于BSD的,BSD為了實(shí)現(xiàn)可靠信號(hào)機(jī)制,又能夠統(tǒng)一對(duì)外接口,用sigaction函數(shù)重新實(shí)現(xiàn)了signal函數(shù))。

(4)消息(Message)隊(duì)列:消息隊(duì)列是消息的鏈接表,包括Posix消息隊(duì)列system V消息隊(duì)列。有足夠權(quán)限的進(jìn)程可以向隊(duì)列中添加消息,被賦予讀權(quán)限的進(jìn)程則可以讀走隊(duì)列中的消息。消息隊(duì)列克服了信號(hào)承載信息量少,管道只能承載無格式字節(jié)流以及緩沖區(qū)大小受限等缺

(5)共享內(nèi)存:使得多個(gè)進(jìn)程可以訪問同一塊內(nèi)存空間,是最快的可用IPC形式。是針對(duì)其他通信機(jī)制運(yùn)行效率較低而設(shè)計(jì)的。往往與其它通信機(jī)制,如信號(hào)量結(jié)合使用,來達(dá)到進(jìn)程間的同步及互斥。

(6)內(nèi)存映射(mapped memory):內(nèi)存映射允許任何多個(gè)進(jìn)程間通信,每一個(gè)使用該機(jī)制的進(jìn)程通過把一個(gè)共享的文件映射到自己的進(jìn)程地址空間來實(shí)現(xiàn)它。

(7)信號(hào)量(semaphore):主要作為進(jìn)程間以及同一進(jìn)程不同線程之間的同步手段。

(8)套接口(Socket):更為一般的進(jìn)程間通信機(jī)制,可用于不同機(jī)器之間的進(jìn)程間通信。起初是由Unix系統(tǒng)的BSD分支開發(fā)出來的,但現(xiàn)在一般可以移植到其它類Unix系統(tǒng)上:Linux和System V的變種都支持套接字。

以上這篇詳談java線程與線程、進(jìn)程與進(jìn)程間通信就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 基于springboot的flowable工作流實(shí)戰(zhàn)流程分析

    基于springboot的flowable工作流實(shí)戰(zhàn)流程分析

    這篇文章主要介紹了基于springboot的flowable工作流實(shí)戰(zhàn)流程分析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-10-10
  • Mybatis防止sql注入原理分析

    Mybatis防止sql注入原理分析

    這篇文章主要介紹了Mybatis防止sql注入原理分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • SpringBoot+Vue靜態(tài)資源刷新后無法訪問的問題解決方案

    SpringBoot+Vue靜態(tài)資源刷新后無法訪問的問題解決方案

    這篇文章主要介紹了SpringBoot+Vue靜態(tài)資源刷新后無法訪問的問題解決方案,文中通過代碼示例和圖文講解的非常詳細(xì),對(duì)大家解決問題有一定的幫助,需要的朋友可以參考下
    2024-05-05
  • Spring事務(wù)管理配置文件問題排查

    Spring事務(wù)管理配置文件問題排查

    這篇文章主要介紹了Spring事務(wù)管理配置文件問題排查,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-05-05
  • SpringCloud?Eureka服務(wù)注冊(cè)中心應(yīng)用入門詳解

    SpringCloud?Eureka服務(wù)注冊(cè)中心應(yīng)用入門詳解

    這篇文章主要介紹了Spring?Cloud?Eureka服務(wù)注冊(cè)中心入門流程分析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • Spring Boot容器加載時(shí)執(zhí)行特定操作(推薦)

    Spring Boot容器加載時(shí)執(zhí)行特定操作(推薦)

    這篇文章主要介紹了Spring Boot容器加載時(shí)執(zhí)行特定操作及spring內(nèi)置的事件,需要的朋友可以參考下
    2018-01-01
  • 深入理解springboot中配置文件application.properties

    深入理解springboot中配置文件application.properties

    本文主要介紹了springboot中配置文件application.properties,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • java三個(gè)環(huán)境變量配置簡單教程

    java三個(gè)環(huán)境變量配置簡單教程

    這篇文章主要為大家詳細(xì)介紹了java三個(gè)環(huán)境變量配置簡單教程,配置path變量、配置classpath變量、最后是配置JAVA_HOME變量,感興趣的小伙伴們可以參考一下
    2016-07-07
  • 淺析Java中ConcurrentHashMap的存儲(chǔ)流程

    淺析Java中ConcurrentHashMap的存儲(chǔ)流程

    ConcurrentHashMap技術(shù)在互聯(lián)網(wǎng)技術(shù)使用如此廣泛,幾乎所有的后端技術(shù)面試官都要在ConcurrentHashMap技術(shù)的使用和原理方面對(duì)小伙伴們進(jìn)行360°的刁難,本文詳細(xì)給大家介紹一下ConcurrentHashMap的存儲(chǔ)流程,需要的朋友可以參考下
    2023-05-05
  • springMVC返回復(fù)雜的json格式數(shù)據(jù)方法

    springMVC返回復(fù)雜的json格式數(shù)據(jù)方法

    下面小編就為大家分享一篇springMVC返回復(fù)雜的json格式數(shù)據(jù)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03

最新評(píng)論