亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

淺談Java多線程實(shí)現(xiàn)及同步互斥通訊

 更新時(shí)間:2017年04月30日 13:26:08   投稿:jingxian  
下面小編就為大家?guī)硪黄獪\談Java多線程實(shí)現(xiàn)及同步互斥通訊。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

Java多線程深入理解本文主要從三個(gè)方面了解和掌握多線程:

1. 多線程的實(shí)現(xiàn)方式,通過繼承Thread類和通過實(shí)現(xiàn)Runnable接口的方式以及異同點(diǎn)。

2. 多線程的同步與互斥中synchronized的使用方法。

3. 多線程的通訊中的notify(),notifyAll(),及wait(),的使用方法,以及簡(jiǎn)單的生成者和消費(fèi)者的代碼實(shí)現(xiàn)。

下面來具體的講解Java中的多線程:

一:多線程的實(shí)現(xiàn)方式

通過繼承Threa類來實(shí)現(xiàn)多線程主要分為以下三步:

第一步:繼承 Thread,實(shí)現(xiàn)Thread類中的run()方法。

第二步:定義一個(gè)Thread子類的實(shí)例。

第三步:通過調(diào)用Thread類的start()方法來啟動(dòng)線程。

下面是簡(jiǎn)單的代碼實(shí)現(xiàn):

class myThread extends Thread{
  int n=100;
  public void run() {
    while (true) {
    if (n > 0) {
System.out.println(":"Thread.currentThread().getName()
              + "..." + n--);
        } else {
          break;
        }
      }
  }

}
public class ThreadTest {

  public static void main(String[] args) {
    myThread mythread=new myThread();
    mythread.setName("子線程");
    mythread.start();
  }

}

上面線程中用到的幾個(gè)方法:Thread.currentThraed().getName()方法得到當(dāng)前線程的名字。mythread.setName(“子線程”);為mythread線程重命名為“子線程”。

通過實(shí)現(xiàn)Runnable 接口來實(shí)現(xiàn)多線程主要分為以下幾步:

第一步:實(shí)現(xiàn)Runnable接口中的run()方法。生成一個(gè)Runnable的實(shí)例。

第二步:定義一個(gè)Thread類,并且將上面的Runnable實(shí)例傳給Thread類的構(gòu)造方法。

第三步:通過調(diào)用Thread類的start()方法來啟動(dòng)線程。

下面是簡(jiǎn)單的代碼實(shí)現(xiàn):

class myRunnable implements Runnable{
  int n=100;
  public void run() {
    while (true) {
    if (n > 0) {
System.out.println(":"Thread.currentThread().getName()
              + "..." + n--);
        } else {
          break;
        }
      }
  }
}
public class ThreadTest {

  public static void main(String[] args) {
    myRunnable myrunnable = new myRunnable();
    Thread mythread=new Thread(myrunnable);
    mythread.setName("子線程");
    mythread.start();
  }
}

既然通過繼承Thread類,和實(shí)現(xiàn)Runnable方法都能實(shí)現(xiàn)多線程的運(yùn)行那么兩種方式到底有什么不同呢?下面通過一個(gè)買票的類子來看看到底二者有什么不同:

假設(shè)售票處總共有100張票,通過三個(gè)窗口來進(jìn)行售票也就是說我們要開辟三個(gè)不同的線程來實(shí)現(xiàn)買票:首先看看通過Thread類來實(shí)現(xiàn)買票的方式:

class myThread extends Thread{
  int n=100;
  public void run() {
    while (true) {
    if (n > 0) {
System.out.println(":"Thread.currentThread().getName()
              + "..." + n--);
        } else {
          break;
        }
      }
  }
}
public class ThreadTest {
  public static void main(String[] args) {
    myThread m1=new myThread();
    myThread m2=new myThread();
    myThread m3=new myThread();
    m1.setName("窗口1");
    m2.setName("窗口2");
    m3.setName("窗口3");
    m1.start();
    m2.start();
    m3.start();
  }
}

結(jié)果太長(zhǎng)了我不展示了,可以看到原本三個(gè)窗口共同買100張票的,但是結(jié)果每個(gè)窗口都買了100張票,這個(gè)很好理解因?yàn)槊總€(gè)窗口都是一個(gè)獨(dú)立的對(duì)象,都有自己的n=100。所以通過Thread類來實(shí)現(xiàn)買票功能是不可行的,其實(shí)用Thread方法來實(shí)現(xiàn)多線程,其中每個(gè)線程執(zhí)行的代碼并不是同一段代碼。

下面來看看實(shí)現(xiàn)Runnable接口是怎樣實(shí)現(xiàn)買票功能的:

class myRunnable implements Runnable{
  int n=100;
  public void run() {
    while (true) {
    if (n > 0) {
System.out.println(":"Thread.currentThread().getName()
              + "..." + n--);
        } else {
          break;
        }
      }
  }
}
public class ThreadTest {
  public static void main(String[] args) {
    myRunnable myrunnable=new myRunnable();
    Thread m1=new Thread(myrunnable);
    Thread m2=new Thread(myrunnable);
    Thread m3=new Thread(myrunnable);
    m1.setName("窗口1");
    m2.setName("窗口2");
    m3.setName("窗口3");
    m1.start();
    m2.start();
    m3.start();
  }
}

可以看出上面三個(gè)線程公用的是同一個(gè)Runnable的子類,所以只是開辟三條線程來執(zhí)行同一段runnable的代碼。所以不會(huì)出現(xiàn)買300張票的情況。但是這個(gè)程序還是有問題的當(dāng)講到了后面的線程的同步與互斥后我們?cè)賮硗晟七@段程序。

二:多線程的同步與互斥中synchronized和volatile的使用方法。

現(xiàn)在截取一段上面代碼執(zhí)行過程中出現(xiàn)的問題并且分析一下問題是如何產(chǎn)生的,再來通過synchronied來解決此問題。

:窗口2…1
:窗口1…1
:窗口3…1
:窗口1…2
:窗口2…2
:窗口1…3
:窗口3…2
:窗口1…4
:窗口2…3
:窗口1…5
:窗口3…3
:窗口1…6
:窗口2…4

上面代碼的結(jié)果是通過實(shí)現(xiàn)Runnable接口產(chǎn)生的,上面窗口1,窗口2,窗口3,同時(shí)產(chǎn)生1是怎么產(chǎn)生的呢?

  int n=100;
  public void run() {
    while (true) {
    if (n > 0) {
System.out.println(":"Thread.currentThread().getName()
              + "..." + n--);
        } else {
          break;
        }
      }

這是三個(gè)線程共同執(zhí)行的同一段代碼,上面結(jié)果產(chǎn)生的一種原因可能是當(dāng)窗口2執(zhí)行完輸出i=1時(shí)此時(shí)虛擬機(jī)執(zhí)行了窗口2,窗口2執(zhí)行輸出I,此時(shí)的i還未執(zhí)行++,所以i的值還是1,此時(shí)虛擬機(jī)又把執(zhí)行權(quán)給了窗口3,這個(gè)時(shí)候窗口3輸出的i仍然是1,程序產(chǎn)生上面問題的主要原因是存在公共變量i,i的值在程序執(zhí)行的過程中未保持同步。上面的for循環(huán)體應(yīng)該單獨(dú)執(zhí)行完之后才能讓其他的線程搶占虛擬機(jī)。Synchronized關(guān)鍵字就是用來實(shí)現(xiàn)保證線程在執(zhí)行一段公共資源是不被其他線程搶占。

被synchronized修飾的代碼塊稱作同步代碼塊,被synchronized修飾的方法稱為同步方法。下面通過加入synchronized關(guān)鍵字來實(shí)現(xiàn)買票功能:

class myRunnable implements Runnable {
  int n = 100;

  public void run() {
    while (true) {
      synchronized (this) {
        if (n > 0) {
          if (n % 10 == 0) {
            try {
              Thread.currentThread().sleep(10);
            } catch (InterruptedException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
            }
          }
          System.out.println(":" + Thread.currentThread().getName()
              + "..." + n--);
        } else {
          break;
        }
      }
    }
  }
}

public class ThreadTest {
  public static void main(String[] args) {
    myRunnable myrunnable = new myRunnable();
    Thread m1 = new Thread(myrunnable);
    Thread m2 = new Thread(myrunnable);
    Thread m3 = new Thread(myrunnable);
    m1.setName("窗口1");
    m2.setName("窗口2");
    m3.setName("窗口3");
    m1.start();
    m2.start();
    m3.start();
  }
}

此時(shí)是可以正確的完成售票功能的。

上面代碼中synchronized(this)中的this代表的是當(dāng)前的對(duì)象,因?yàn)槿齻€(gè)線程執(zhí)行的都是myRunnable 的對(duì)象,所以三個(gè)線程公用的是同一個(gè)鎖,其實(shí)這個(gè)this可以用任何的對(duì)象來代替,一般我們可以 String str=new String(“”);雖然str的值為空字符串,但是也是一個(gè)對(duì)象。Synchronized實(shí)現(xiàn)互斥的原理是每一個(gè)對(duì)象都有一個(gè)特定的變量值,當(dāng)任何一個(gè)線程調(diào)用了synchronized想要進(jìn)入公共資源區(qū)時(shí),先判斷該變量的值,若該變量的值為0則可以進(jìn)入公共資源區(qū),進(jìn)程在進(jìn)入公共資源區(qū)之前先把對(duì)象的中的該變量值變?yōu)?,出同步區(qū)后再將該變量的值變?yōu)?,從而實(shí)現(xiàn)線程互斥訪問公共資源。

三:多線程的通訊中的notify(),notifyAll(),及wait(),的使用方法,以及簡(jiǎn)單的生成者和消費(fèi)者的代碼實(shí)現(xiàn)。

在講解notify(),notifyAll(),wait()之前,先看看生產(chǎn)者和消費(fèi)者問題:生產(chǎn)者生產(chǎn)面包,消費(fèi)者消費(fèi)面包,但是存放面包的容器有限,生產(chǎn)者一次最多只能生產(chǎn)20個(gè)面包,消費(fèi)者每次在容器中拿一個(gè)面包。通過分析可以知道,當(dāng)生產(chǎn)者生產(chǎn)了20個(gè)面包之后必須停下來,等容器里的面包數(shù)目小于20個(gè)時(shí)再繼續(xù)生產(chǎn),消費(fèi)者看到容器里面面包個(gè)數(shù)為0時(shí)也必須停下來,等到有面包時(shí)才能消費(fèi)。這時(shí)候就涉及到了生產(chǎn)者和消費(fèi)者的通信。notify()是用于喚醒等待隊(duì)列中的線程,wait()用于阻塞當(dāng)前線程。Notify和wait()都必須用于synchronized修飾的同步代碼塊或同步方法中。

下面直接看生產(chǎn)者消費(fèi)者代碼。

class Consumer implements Runnable {
  Clerk clerk;
  Consumer(Clerk clerk) {
    this.clerk = clerk;
  }
  public void run() {
    while(true)
    clerk.consumeProduct();
  }
}
class Producter implements Runnable {
  Clerk clerk;
  Producter(Clerk clerk)
  {
    this.clerk = clerk;
  }
  public void run() {
    while(true)
    clerk.addProduct();
  }
}
class Clerk {
  int product ;
  public synchronized void consumeProduct() {
    while (true) {
      if (product <= 0) {
        try {
          wait();
        } catch (InterruptedException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      } else {
        product--;
        notifyAll();
        System.out.println("消費(fèi)者消費(fèi)了:" + product);
      }
    }
  }
  public synchronized void addProduct() {
    if (product > 20) {
      try {
        wait();
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    } else {
      product++;
      notifyAll();
      System.out.println("生產(chǎn)者生產(chǎn)了:" + product);
    }
  }

}
public class Test {
  public static void main(String[] args) {
    Clerk clerk=new Clerk();
    Consumer consumer=new Consumer(clerk);
    Thread c=new Thread(consumer);
    Producter producter=new Producter(clerk);
    Thread p=new Thread(producter);
    c.start();
    p.start();
  }
}


以上這篇淺談Java多線程實(shí)現(xiàn)及同步互斥通訊就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Mybatis持久層框架入門之CRUD實(shí)例代碼詳解

    Mybatis持久層框架入門之CRUD實(shí)例代碼詳解

    這篇文章主要介紹了Mybatis持久層框架入門之CRUD實(shí)例,需要的朋友可以參考下
    2022-05-05
  • SpringBoot整合RabbitMQ實(shí)現(xiàn)消息確認(rèn)機(jī)制

    SpringBoot整合RabbitMQ實(shí)現(xiàn)消息確認(rèn)機(jī)制

    這篇文章主要介紹了SpringBoot整合RabbitMQ實(shí)現(xiàn)消息確認(rèn)機(jī)制,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-08-08
  • javaWeb項(xiàng)目部署到阿里云服務(wù)Linux系統(tǒng)的詳細(xì)步驟

    javaWeb項(xiàng)目部署到阿里云服務(wù)Linux系統(tǒng)的詳細(xì)步驟

    這篇文章主要介紹了javaWeb項(xiàng)目部署到阿里云服務(wù)Linux系統(tǒng),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • Java實(shí)現(xiàn)駝峰、下劃線互轉(zhuǎn)的方法

    Java實(shí)現(xiàn)駝峰、下劃線互轉(zhuǎn)的方法

    這篇文章主要介紹了Java實(shí)現(xiàn)駝峰、下劃線互轉(zhuǎn)的示例代碼,主要有使用 Guava 實(shí)現(xiàn)和自定義代碼轉(zhuǎn),本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05
  • springboot使用定時(shí)器@Scheduled不管用的解決

    springboot使用定時(shí)器@Scheduled不管用的解決

    這篇文章主要介紹了springboot使用定時(shí)器@Scheduled不管用的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java中圖像銳化操作的方法詳解

    Java中圖像銳化操作的方法詳解

    這篇文章主要給大家介紹了關(guān)于Java中圖像銳化操作的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Java異常處理的五個(gè)關(guān)鍵字

    Java異常處理的五個(gè)關(guān)鍵字

    本篇文章給大家詳細(xì)講述了關(guān)于Java異常處理的相關(guān)知識(shí)點(diǎn),并列舉了5個(gè)重要關(guān)鍵字,一起啊參考學(xué)下。
    2018-03-03
  • 使用Mybatis接收Integer參數(shù)的問題

    使用Mybatis接收Integer參數(shù)的問題

    這篇文章主要介紹了使用Mybatis接收Integer參數(shù)的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • java8如何用Stream查L(zhǎng)ist對(duì)象某屬性是否有重復(fù)

    java8如何用Stream查L(zhǎng)ist對(duì)象某屬性是否有重復(fù)

    這篇文章主要介紹了java8如何用Stream查L(zhǎng)ist對(duì)象某屬性是否有重復(fù)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • SpringBoot接受前臺(tái)參數(shù)的6種方式以及統(tǒng)一響應(yīng)代碼示例

    SpringBoot接受前臺(tái)參數(shù)的6種方式以及統(tǒng)一響應(yīng)代碼示例

    這篇文章主要給大家介紹了關(guān)于SpringBoot接受前臺(tái)參數(shù)的6種方式以及統(tǒng)一響應(yīng)的相關(guān)資料,前端負(fù)責(zé)展示頁面和用戶交互,而后端則負(fù)責(zé)處理業(yè)務(wù)邏輯和數(shù)據(jù)存儲(chǔ),在這種架構(gòu)下前端需要將用戶輸入的數(shù)據(jù)發(fā)送給后端進(jìn)行處理,需要的朋友可以參考下
    2023-12-12

最新評(píng)論