一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - 基于線程、并發(fā)的基本概念(詳解)

基于線程、并發(fā)的基本概念(詳解)

2020-11-02 17:43Java教程網(wǎng) Java教程

下面小編就為大家?guī)硪黄诰€程、并發(fā)的基本概念(詳解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

什么是線程

提到“線程”總免不了要和“進(jìn)程”做比較,而我認(rèn)為在Java并發(fā)編程中混淆的不是“線程”和“進(jìn)程”的區(qū)別,而是“任務(wù)(Task)”。進(jìn)程是表示資源分配的基本單位。而線程則是進(jìn)程中執(zhí)行運(yùn)算的最小單位,即執(zhí)行處理機(jī)調(diào)度的基本單位。關(guān)于“線程”和“進(jìn)程”的區(qū)別耳熟能詳,說來說去就一句話:通常來講一個(gè)程序有一個(gè)進(jìn)程,而一個(gè)進(jìn)程可以有多個(gè)線程。

但是“任務(wù)”是很容易忽略的一個(gè)概念。我們在實(shí)際編碼中通常會(huì)看到這么一個(gè)包叫做xxx.xxx.task,包下是XxxTask等等以Task后綴名結(jié)尾的類。而XxxTask類通常都是實(shí)現(xiàn)Runnable接口或者Thread類。嚴(yán)格來說,“任務(wù)”和并發(fā)編程沒多大關(guān)系,就算是單線程結(jié)構(gòu)化順序編程中,我們也可以定義一個(gè)Task類,在類中執(zhí)行我們想要完成的一系列操作。“任務(wù)”我認(rèn)為是我們?nèi)藶槎x的一個(gè)概念,既抽象又具體,抽象在它指由軟件完成的一個(gè)活動(dòng),它可以是一個(gè)線程,也可以是多個(gè)線程共同達(dá)到某一目的的操作,具體在于它是我們認(rèn)為指定實(shí)實(shí)在在的操作,例如:定時(shí)獲取天氣任務(wù)(定時(shí)任務(wù)),下線任務(wù)……關(guān)鍵就在于不要認(rèn)為一個(gè)任務(wù)對應(yīng)的就是一個(gè)線程,也許它是多個(gè)線程,甚至在這個(gè)任務(wù)中是一個(gè)線程池,這個(gè)線程池處理這個(gè)我們定義的操作。

我產(chǎn)生“線程”和“任務(wù)”的疑惑就是在《Thinking in Java》這本書的“并發(fā)”章節(jié)中它將線程直接定義為一個(gè)任務(wù),在開篇標(biāo)題就取名為“定義任務(wù)”,并且提到定義任務(wù)只需實(shí)現(xiàn)Runnable接口.而這個(gè)任務(wù)則是通過調(diào)用start來創(chuàng)建一改新的線程來執(zhí)行.說來說去有點(diǎn)繞,其實(shí)也不必糾結(jié)于在書中時(shí)而提到線程,時(shí)而提到人任務(wù).我認(rèn)為就記住:任務(wù)是我們在編程時(shí)所賦這段代碼的實(shí)際意義,而線程就關(guān)注它是否安全,是否需要安全,這就是后面要提到的線程安全問題.在像我一樣產(chǎn)生疑惑時(shí),不用在意它兩者間的關(guān)系和提法。

什么是并發(fā)?

提到了并發(fā),那又不得不和并行作比較。并發(fā)是指在一段時(shí)間內(nèi)同時(shí)做多個(gè)事情,比如在1點(diǎn)-2點(diǎn)洗碗、洗衣服等。而并行是指在同一時(shí)刻做多個(gè)事情,比如1點(diǎn)我左手畫圓右手畫方。兩個(gè)很重要的區(qū)別就是“一段時(shí)間”和“同一時(shí)刻”.在操作系統(tǒng)中就是:

1) 并發(fā)就是在單核處理中同時(shí)處理多個(gè)任務(wù)。(這里的同時(shí)指的是邏輯上的同時(shí))

2) 并行就是在多核處理器中同時(shí)處理多個(gè)任務(wù)。(這里的同時(shí)指的就是物理上的同時(shí))

初學(xué)編程基本上都是單線程結(jié)構(gòu)化編程,或者說是根本就接觸不到線程這個(gè)概念,反正程序照著自己實(shí)現(xiàn)的邏輯,程序一步一步按照我們的邏輯去實(shí)現(xiàn)并且得到希望輸出的結(jié)果。但隨著編程能力的提高,以及應(yīng)用場景的復(fù)雜多變,我們不得不要面臨多線程并發(fā)編程。而初學(xué)多線程并發(fā)編程時(shí),常常出現(xiàn)一些預(yù)料之外的結(jié)果,這就是涉及到“線程安全”問題。

什么線程安全?

這是在多線程并發(fā)編程中需要引起足夠重視的問題,如果你的線程不足夠“安全”,程序就可能出現(xiàn)難以預(yù)料,以及難以復(fù)現(xiàn)的結(jié)果。《Java并發(fā)編程實(shí)戰(zhàn)》提到對線程安全不好做一個(gè)定義,我的簡單理解就是:線程安全就是指程序按照你的代碼邏輯執(zhí)行,并始終輸出預(yù)定的結(jié)果。書中的給的定義:當(dāng)多個(gè)線程訪問某個(gè)類時(shí),這個(gè)類始終都能表現(xiàn)出正確的行為,那么就稱這個(gè)類是線程安全的。具體有關(guān)線程安全的問題,例如原子性、可見性等等不在這里做詳細(xì)闡述,適當(dāng)?shù)臅r(shí)候會(huì)進(jìn)行詳細(xì)介紹,簡單說一點(diǎn),想要這個(gè)線程安全,得在訪問的時(shí)候給它上個(gè)鎖,不讓其他線程訪問,當(dāng)然這種說法不嚴(yán)謹(jǐn),不過可以暫時(shí)這么理解。

以上是從基本概念理論出發(fā)來大致了解需要知道的一些概念,下面就針對JDK中有關(guān)線程的API來對多線程并發(fā)編程做一個(gè)了解。

?
1
2
3
4
5
6
java.lang.Object
  -public void notify()//喚醒這個(gè)對象監(jiān)視器正在等待獲取鎖的一個(gè)線程
  -public void notifyAll()//喚醒這個(gè)對象監(jiān)視器上正在等待獲取鎖的所有線程
  -public void wait()//導(dǎo)致當(dāng)前線程等待另一個(gè)線程調(diào)用notify()或notifyAll()
  -public void wait(long timeout)// 導(dǎo)致當(dāng)前線程等待另一個(gè)線程調(diào)用notify()或notifyAll(),或者達(dá)到timeout時(shí)間
  -public void wait(long timeout, int nanos)//與上個(gè)方法相同,只是將時(shí)間控制到了納秒nanos

我們先用一個(gè)經(jīng)典的例子——生產(chǎn)者消費(fèi)者問題來說明上面的API是如何使用的。生產(chǎn)者消費(fèi)者問題指的的是,生產(chǎn)者生產(chǎn)產(chǎn)品到倉庫里,消費(fèi)者從倉庫中拿,倉庫滿時(shí)生產(chǎn)者不能繼續(xù)生產(chǎn),倉庫為空時(shí)消費(fèi)者不能繼續(xù)消費(fèi)。轉(zhuǎn)化成程序語言也就是生產(chǎn)者是一個(gè)線程

1,消費(fèi)者是線程

2,倉庫是一個(gè)隊(duì)列,線程1往隊(duì)尾中新增,線程2從隊(duì)首中移除,隊(duì)列滿時(shí)線程1不能再新增,隊(duì)列空時(shí)線程2不能再移除。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package com.producerconsumer;
 
import java.util.Queue;
 
 
 
/**
 
 * 生產(chǎn)者
 
 * Created by yulinfeng on 2017/5/11.
 
 */
 
public class Producer implements Runnable{
 
  private final Queue<String> queue;
 
  private final int maxSize;
 
  public Producer(Queue<String> queue, int maxSize) {
 
    this.queue = queue;
 
    this.maxSize = maxSize;
 
  }
  public void run() {
    produce();
  }
 
  /**
 
   * 生產(chǎn)
 
   */
 
  private void produce() {
 
    try {
      while (true) {
        synchronized (queue) {
          if (queue.size() == maxSize) {
            System.out.println("生產(chǎn)者:倉庫滿了,等待消費(fèi)者消費(fèi)");
            queue.wait();
          }
          System.out.println("生產(chǎn)者:" + queue.add("product"));
          queue.notifyAll();
        }
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}
 
 
 
package com.producerconsumer;
 
import java.util.Queue;
 
/**
 
 * 消費(fèi)者
 
 * Created by yulinfeng on 2017/5/11.
 
 */
 
public class Consumer implements Runnable {
 
  private final Queue<String> queue;
  public Consumer(Queue<String> queue) {
    this.queue = queue;
  }
 
  public void run() {
    consume();
  }
 
 
 
  /**
 
   * 消費(fèi)
 
   */
 
  private void consume() {
    synchronized (queue) {
      try {
        while (true) {
          if (queue.isEmpty()) {
            System.out.println("消費(fèi)者:倉庫空了,等待生產(chǎn)者生產(chǎn)");
            queue.wait();
          }
          System.out.println("消費(fèi)者:" + queue.remove());
          queue.notifyAll();
        }
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
 
}
 
 
 
package com.producerconsumer;
 
import java.util.LinkedList;
import java.util.Queue;
 
/**
 
 * Created by yulinfeng on 2017/5/11.
 
 */
 
public class Main {
 
  public static void main(String[] args) {
 
    Queue<String> queue = new LinkedList<String>();
    int maxSize = 100;
    Thread producer = new Thread(new Producer(queue, maxSize));
    Thread consumer = new Thread(new Consumer(queue));
    producer.start();
    consumer.start();
 
  }
 
}

基于線程、并發(fā)的基本概念(詳解) 

這個(gè)生產(chǎn)者消費(fèi)者問題的實(shí)現(xiàn),我采用線程不安全的LinkedList,使用內(nèi)置鎖synchronized來保證線程安全,在這里我們不討論synchronized,主要談notify()、notifyAll()和wait()。

在這里例子中,作為生產(chǎn)者,當(dāng)隊(duì)列滿時(shí)調(diào)用了隊(duì)列的wait()方法,表示等待,并且此時(shí)釋放了鎖。作為消費(fèi)者此時(shí)獲取到鎖并且移除隊(duì)首元素時(shí)調(diào)用了notifyAll()方法,此時(shí)生產(chǎn)者由wait等待狀態(tài)轉(zhuǎn)換為喚醒狀態(tài),但注意!此時(shí)僅僅是線程被喚醒了,有了爭奪CPU資源的資格,并不代表下一步就一定是生產(chǎn)者生產(chǎn),還有可能消費(fèi)者繼續(xù)爭奪了CPU資源。一定記住是被喚醒了,有資格爭奪CPU資源。notifyAll()表示的是喚醒所有等待的線程,所有等待的線程被喚醒過后,都有了爭奪CPU資源的權(quán)利,至于是誰會(huì)獲得這個(gè)鎖,那不一定。而如果是使用notify(),那就代表喚醒所有等待線程中的一個(gè),只是一個(gè)被喚醒具有了爭奪CPU的權(quán)力,其他沒被喚醒的線程繼續(xù)等待。如果等待線程就只有一個(gè)那么notify()和notifyAll()就沒區(qū)別,不止一個(gè)那區(qū)別就大了,一個(gè)是只喚醒其中一個(gè),一個(gè)是喚醒所有。喚醒不是代表這個(gè)線程就一定獲得CPU資源一定獲得鎖,而是有了爭奪的權(quán)利。

?
1
2
3
4
5
java.lang.Thread
  -public void join()
  -public void sleep()
  -public static void yield()
  -……

針對Thread線程類,我們只說常見的幾個(gè)不容易理解的方法,其余方法不在這里做詳細(xì)闡述。

關(guān)于sleep()方法,可能很容易拿它和Object的wait方法作比較。兩個(gè)方法很重要的一點(diǎn)就是sleep不會(huì)釋放鎖,而wait會(huì)釋放鎖。在上面的生產(chǎn)者消費(fèi)者的生產(chǎn)或消費(fèi)過程中添加一行Thread.sleep(5000),你將會(huì)發(fā)現(xiàn)執(zhí)行到此處時(shí),這個(gè)跟程序都會(huì)暫停執(zhí)行5秒,不會(huì)有任何其他線程執(zhí)行,因?yàn)樗粫?huì)釋放鎖。

關(guān)于join()方法,JDK7的解釋是等待線程結(jié)束(Waits for this thread to die)似乎還是不好理解,我們在main函數(shù)中啟動(dòng)兩個(gè)線程,在啟動(dòng)完這兩個(gè)線程后main函數(shù)再執(zhí)行其他操作,但如果不加以限制,有可能main函數(shù)率先執(zhí)行完需要的操作,但如果在main函數(shù)中加入join方法,則表示阻塞等待這兩個(gè)線程執(zhí)行結(jié)束后再執(zhí)行main函數(shù)后的操作,例如:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.join;
 
 
public class Main {
 
  public static void main(String[] args) throws Exception{
    Thread t1 = new Thread(new Task(0));
    Thread t2 = new Thread(new Task(0));
    t1.start();
    t2.start();
    t1.join();
    t2.join();
    System.out.print("main結(jié)束");
  }
}

上面?zhèn)€例子如果沒有join方法,那么“main”結(jié)束這條輸出語句可能就會(huì)先于t1、t2,加上在啟動(dòng)線程的調(diào)用方使用了線程的join方法,則調(diào)用方則會(huì)阻塞線程執(zhí)行結(jié)束過后再執(zhí)行剩余的方法。

關(guān)于Thread.yield()方法,本來這個(gè)線程處于執(zhí)行狀態(tài),其他線程也想爭奪這個(gè)資源,突然,這個(gè)線程不想執(zhí)行了想和大家一起來重新奪取CPU資源。所以Thread.yield也稱讓步。從下一章開始就正式開始了解java.util.concurrent。

以上這篇基于線程、并發(fā)的基本概念(詳解)就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持服務(wù)器之家。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 福利国产片 | 毛片网在线观看 | 91成人啪国产啪永久地址 | 男同桌扒开女同桌胸罩喝奶 | 91桃色视频 | 亚洲午夜精品久久久久久成年 | www.在线观看视频 | 成人伊人亚洲人综合网站222 | 日本一卡二卡3卡四卡无卡网址 | 50度灰破解版v5.7.0 | 精品国产精品人妻久久无码五月天 | 国产精品手机视频一区二区 | 国产精品一区二区三 | 五月天久久久 | 四虎永久免费在线观看 | 私人影院免费观看 | 性一交一乱一伧老太 | 掰开逼操 | 91香蕉官网 | 男女性潮高片无遮挡禁18 | 午夜dj影院在线观看完整版 | 国产精品66福利在线观看 | 日韩欧美a| 亚洲国产在线2o20 | 国产精品久线观看视频 | 精品一区二区高清在线观看 | 国产成人免费视频 | 色色色资源站 | 国产精品自在欧美一区 | 好大好长好紧爽免费 | 欧美vpswindows | 精品久久久久久国产 | 胖女性大bbbbbb | 日韩亚洲国产欧美精品 | 女人用粗大自熨喷水在线视频 | 色悠久久久久综合欧美99 | naruto堂同人本子汉化gg | 99精品国产高清自在线看超 | 天堂8在线天堂资源bt | 亚洲精品国产精麻豆久久99 | 久久国产精品无码视欧美 |