多線程和線程同步

線程和進(jìn)程

進(jìn)程和線程
  • 操作系統(tǒng)中運(yùn)行的多個(gè)軟件丰包,一個(gè)軟件相當(dāng)于一個(gè)進(jìn)程(進(jìn)程間的數(shù)據(jù)不共享)

  • 一個(gè)運(yùn)行中的軟件可能包含多個(gè)進(jìn)程(android:multiprocess/android:process)

  • 一個(gè)運(yùn)行中的進(jìn)程可能包含多個(gè)線程(線程間的部分?jǐn)?shù)據(jù)可以共享)

CPU線程和操作系統(tǒng)線程

CPU線程:

  • 多核CPU的每個(gè)核各自獨(dú)立運(yùn)行俭识,因此每個(gè)核一個(gè)線程

  • 四核八線程:CPU硬件方在硬件級(jí)別對(duì)CPU進(jìn)行了一核多線程的支持(本質(zhì)上依然是每個(gè)核一個(gè)線程)

操作系統(tǒng)線程:

  • 操作系統(tǒng)利用時(shí)間分片的方式髓霞,把CPU的運(yùn)行拆分給多條運(yùn)行邏輯,即為操作系統(tǒng)的線程

單核CPU也可以利用時(shí)間分片方式運(yùn)行多線程操作系統(tǒng)

線程是什么
  • 按代碼順序執(zhí)行下來,執(zhí)行完畢就結(jié)束的一條線

  • UI線程為什么不會(huì)結(jié)束?因?yàn)樗诔跏蓟戤吅蠡趫?zhí)行死循環(huán),循環(huán)的內(nèi)容是刷線界面

多線程的使用

Thread
Thread thread = new Thread() {
  @Override
  public void run() {
      super.run();  //執(zhí)行Runnable的run()方法
      System.out.println("Thread start");
  }
   };

thread.start();
Runnable
Thread thread = new Thread(new Runnable() {
  @Override
  public void run() {
      System.out.println("Thread with runnable start");
  }
});

thread.start();
ThreadFactory
ThreadFactory threadFactory = new ThreadFactory() {
  int count = 0;  //線程安全問題
  @Override
  public Thread newThread(Runnable r) {
      count++;
      return new Thread(r, "Thread-" + count);
  }
};

Runnable runnable = new Runnable() {
  @Override
  public void run() {
      System.out.println(Thread.currentThread().getName() + " start");
  }
};

threadFactory.newThread(runnable).start();
threadFactory.newThread(runnable).start();
threadFactory.newThread(runnable).start();
Executor線程池
  • Executors.newCachedThreadPool() 常用帶緩存的線程池

  • Executors.newFixedThreadPool(20) 短時(shí)批量處理線程池淤井,加快處理速度

  • Executors.newSingleThreadExecutor() 單個(gè)線程的線程池

  • Executors.newSingleThreadScheduledExecutor() 具有定時(shí)功能的單線程線程池

  • Executors.newScheduledThreadPool(20) 具有定時(shí)功能的線程池

Runnable runnable = new Runnable() {
  @Override
  public void run() {
      System.out.println(Thread.currentThread().getName());
  }
};

ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(runnable);
executorService.execute(runnable);
executorService.execute(runnable);

executorService.shutdown();
Callable和Future
  • 帶返回值的線程,獲取返回值時(shí)會(huì)阻塞當(dāng)前線程摊趾,但是可以用while輪詢?nèi)プ銎渌?/li>
Callable<String> callable = new Callable<String>() {
  @Override
  public String call() throws Exception {

      try {
          Thread.sleep(1500);
      } catch (InterruptedException e) {
          e.printStackTrace();
      }

      return "Done";
  }
};

ExecutorService executorService = Executors.newCachedThreadPool();
Future<String> future = executorService.submit(callable);

try {
  String result = future.get();
  System.out.println("result = " + result);
} catch (ExecutionException | InterruptedException e) {
  e.printStackTrace();
} finally {
  executorService.shutdown();
}

線程同步與線程安全

synchronized
  • synchronized方法(該方法互斥訪問)
private synchronized void count(int newValue) {
  x = newValue;
  y = newValue;

  if (x != y) {
      System.out.println("x = " + x + ",      y = " + y);
  }
}
  • synchronized代碼塊(該代碼塊互斥訪問)
private void count(int newValue) {
  synchronized (this){
      x = newValue;
      y = newValue;
      }

  if (x != y) {
      System.out.println("x = " + x + ",  y = " + y);
  }
}
  • synchronized靜態(tài)方法(該類互斥訪問)
public static synchronized void count(int newValue) {
  x = newValue;
  y = newValue;

  if (x != y) {
      System.out.println("x = " + x + ",      y = " + y);
  }
}
  • synchronized 的本質(zhì)
  • 保證方法內(nèi)部或代碼塊內(nèi)部的資源(數(shù)據(jù))的互斥訪問币狠。即同一時(shí)間,由同一個(gè)Monitor監(jiān)視的代碼砾层,最多只能有一個(gè)線程在訪問
  • 保證線程之間對(duì)監(jiān)視資源的數(shù)據(jù)同步漩绵。即任何線程在獲取到Monitor后的第一時(shí)間,會(huì)先將共享內(nèi)存中的數(shù)據(jù)復(fù)制到自己的緩存中肛炮;任何線程在釋放Monitor的第一時(shí)間止吐,會(huì)先將緩存中的數(shù)據(jù)復(fù)制到共享內(nèi)存中
volatile
  • 保證加了volatile關(guān)鍵字的字段的操作具有同步性宝踪,以及對(duì)longdouble的操作的原子性。因此volatile可以看做簡化版的synchronized

  • volatile只對(duì)基本類型(byte,char,short,int,long,float,double,boolean)的賦值操作和對(duì)象的引用賦值操作有效碍扔,但你若要修改User.name是不能保證同步的

  • volatile依然解決不了++的原子性問題

java.util.concurrent.atomic包
  • 里面有AtomicInteger瘩燥, AtomicBoolean 等類,作用和volatile基本一致不同,可以看做是通用版的 volatile
AtomicInteger num = new AtomicInteger(0);
......
num.getAndIncrement();
Lock & ReentrantReadWriteLock
  • 同樣是加鎖機(jī)制颤芬,但使用方式更靈活,同時(shí)也更麻煩一些
Lock lock = new ReentrantLock();
......
lock.lock();
try {
  x++;
} finally{
  //保證在方法在提前結(jié)束或出現(xiàn)Exception的時(shí)候套鹅,依然能正常釋放鎖
  lock.unlock();
}
  • 一般會(huì)使用更加復(fù)雜的鎖,例如 ReadWriteLock
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
Lock readLock = lock.readLock();
Lock writeLock = lock.writeLock();
private int x = 0;

/*** 寫操作加鎖 */
private void count(){
  writeLock.lock();
  try {
      x++;
      } finally{
          writeLock.unlock();
      }
}

/*** 讀操作加鎖 */
private void print (int time) {
  readLock.lock();
  try{
      for (int i = 0; i< time; i++){
          System.out.print(x + " ");
          }
          System.out.println();
      } finally {
          readLock.unlock();
      }
}
線程安全問題的本質(zhì)

在多個(gè)線程訪問共同的資源時(shí)汰具,在某一個(gè)線程對(duì)資源進(jìn)行寫操作的途中(寫操作已經(jīng)開始卓鹿,但是還沒有結(jié)束),其它線程對(duì)這個(gè)寫入了一半的資源進(jìn)行了讀操作留荔,或者基于這個(gè)寫了一半的資源進(jìn)行了寫操作吟孙,導(dǎo)致出現(xiàn)數(shù)據(jù)錯(cuò)誤

鎖機(jī)制的本質(zhì)

通過對(duì)共享資源進(jìn)行訪問限制,讓同一時(shí)間只有一個(gè)線程可以訪問資源聚蝶,保證了數(shù)據(jù)的準(zhǔn)確性

不論是線程安全問題杰妓,還是針對(duì)線程安全問題所衍生出的鎖機(jī)制,它們的核心都在于共享的資源碘勉,而不是某個(gè)方法或者某幾行代碼

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末巷挥,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子验靡,更是在濱河造成了極大的恐慌倍宾,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胜嗓,死亡現(xiàn)場離奇詭異高职,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)辞州,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門怔锌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人变过,你說我怎么就攤上這事埃元。” “怎么了媚狰?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵亚情,是天一觀的道長。 經(jīng)常有香客問我哈雏,道長楞件,這世上最難降的妖魔是什么衫生? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮土浸,結(jié)果婚禮上罪针,老公的妹妹穿的比我還像新娘。我一直安慰自己黄伊,他們只是感情好泪酱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著还最,像睡著了一般墓阀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拓轻,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天斯撮,我揣著相機(jī)與錄音,去河邊找鬼扶叉。 笑死勿锅,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的枣氧。 我是一名探鬼主播溢十,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼达吞!你這毒婦竟也來了张弛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤酪劫,失蹤者是張志新(化名)和其女友劉穎乌庶,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體契耿,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瞒大,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了搪桂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片透敌。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖踢械,靈堂內(nèi)的尸體忽然破棺而出酗电,到底是詐尸還是另有隱情,我是刑警寧澤内列,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布撵术,位于F島的核電站,受9級(jí)特大地震影響话瞧,放射性物質(zhì)發(fā)生泄漏嫩与。R本人自食惡果不足惜寝姿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望划滋。 院中可真熱鬧饵筑,春花似錦、人聲如沸处坪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽同窘。三九已至玄帕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間想邦,已是汗流浹背裤纹。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留案狠,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓钱雷,卻偏偏與公主長得像骂铁,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子罩抗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Java-Review-Note——4.多線程 標(biāo)簽: JavaStudy PS:本來是分開三篇的拉庵,后來想想還是整...
    coder_pig閱讀 1,653評(píng)論 2 17
  • 一、wait--notify--sleep Object obj = new Object(); obj.wait...
    fe0180bd6eaf閱讀 338評(píng)論 0 1
  • JUC 原創(chuàng)者:文思套蒂,感謝尚硅谷钞支,資料來源于尚硅谷 目錄: 1、volatile關(guān)鍵字與內(nèi)存可見性 2操刀、原子變量與...
    文思li閱讀 2,319評(píng)論 0 1
  • 線程池ThreadPoolExecutor corepoolsize:核心池的大小烁挟,默認(rèn)情況下,在創(chuàng)建了線程池之后...
    irckwk1閱讀 728評(píng)論 0 0
  • 引 如果對(duì)什么是線程、什么是進(jìn)程仍存有疑惑欢唾,請(qǐng)先Google之且警,因?yàn)檫@兩個(gè)概念不在本文的范圍之內(nèi)。 用多線程只有一...
    ToEnd閱讀 1,756評(píng)論 1 8