亚洲国产精品无码久久大片,亚洲AV无码乱码麻豆精品国产,亚洲品质自拍网站,少妇伦子伦精品无码STYLES,国产精久久久久久久

系統變量

系統變量

java并發(fā)編程 線(xiàn)程基礎/線(xiàn)程之間的共享和協(xié)作

采集交流 ? 優(yōu)采云 發(fā)表了文章 ? 0 個(gè)評論 ? 339 次瀏覽 ? 2020-04-05 11:36 ? 來(lái)自相關(guān)話(huà)題

  
  一言以蔽之:Java 并發(fā)編程的目的就是充分利用計算機的資源,把計算機的性能發(fā)揮到最大
  
  什么是高并發(fā)
  并發(fā) concurrency 和并行 parallelism 的區別
  并發(fā)是指多個(gè)線(xiàn)程操作同一個(gè)資源,不是同時(shí)操作,而是交替操作,單核 CPU,只不過(guò)由于速率很快,看起來(lái)是同時(shí)執行(張三、李四,共用一口鍋煮飯,交替執行),通過(guò)時(shí)間片輪轉機制RR調度實(shí)現并發(fā)。
  速度很快,看起來(lái)象是并行。
  并行才是真正的同時(shí)執行,多核 CPU,每個(gè)線(xiàn)程使用一個(gè)獨立的 CPU 的資源來(lái)運行。(張三、李四,一人一口鍋,一起燉肉)
  并發(fā)編程是指使系統容許多個(gè)任務(wù)在重疊的時(shí)間段內執行的設計結構。
  高并發(fā)我們設計的程序,可以支持海量任務(wù)的同時(shí)執行(任務(wù)的執行在時(shí)間段上有重疊的情況)
  QPS:每秒響應的懇求數,QPS 并不是并發(fā)數。
  吞吐量:?jiǎn)挝粫r(shí)間內處理的懇求數,QPS 和并發(fā)數決定。
  平均響應時(shí)間:系統對一個(gè)懇求做出響應的平均時(shí)間,QPS = 并發(fā)數/平均響應時(shí)間
  并發(fā)用戶(hù)數:系統可以承載的最大用戶(hù)數目。
  高并發(fā)編程優(yōu)劣
  利:充分利用cpu的資源、加快用戶(hù)響應的時(shí)間,程序模塊化,異步化
  弊:線(xiàn)程共享資源,存在沖突。容易造成死鎖。 啟用太多的線(xiàn)程,就有扳倒機器的可能。
  互聯(lián)網(wǎng)項目構架中,如何提升系統的并發(fā)能力?
  垂直擴充
  水平擴充
  垂直擴充
  提升單機的處理能力
  1、增強單機的硬件性能:增加 CPU 的核數,硬盤(pán)擴容,內存升級。
  2、提升系統的構架性能:使用 Cache 來(lái)提升效率,異步懇求降低單個(gè)服務(wù)的吞吐量,使用 NoSQL 來(lái)提高數據的訪(fǎng)問(wèn)性能。
  水平擴充
  集群、分布式都是水平擴充的方案
  集群:多個(gè)人做同一件事情(3 個(gè)面點(diǎn)師同時(shí)燉肉)
  分布式:把一件復雜的事情,拆分成幾個(gè)簡(jiǎn)單的步驟,分別找不同的人去完成 (1 洗菜、2 切菜、3 炒菜)
  
  
  分布式是指多個(gè)系統協(xié)同合作完成一個(gè)特定任務(wù)的系統。分布式解決問(wèn)題,把所有解決中心化管理的任務(wù)疊加到一個(gè)節點(diǎn)處理,太慢了。把一個(gè)業(yè)務(wù)分拆為多個(gè)子業(yè)務(wù)(當某個(gè)子業(yè)務(wù)訪(fǎng)問(wèn)量突增時(shí),增加該子任務(wù)的節點(diǎn)數即可),部署在多個(gè)服務(wù)器上 ,分布式的主要工作是分解任務(wù),將職能拆解。
  集群主要的使用場(chǎng)景是為了分擔懇求的壓力,同一個(gè)業(yè)務(wù),部署在多個(gè)服務(wù)器上 ,也就是在幾個(gè)服務(wù)器上布署來(lái)==相同的應用程序,==分擔客戶(hù)端懇求。當壓力進(jìn)一步減小的時(shí)侯,可能在須要儲存的部份,mysql 無(wú)法面對好多的寫(xiě)壓力。因為在 mysql 做成集群以后,主要的寫(xiě)壓力還是在 master 的機器里面,其他 slave 機器難以分擔寫(xiě)壓力,從而這個(gè)時(shí)侯,也就引下來(lái)分布式。分布式的主要應用場(chǎng)景是單臺機器早已未能滿(mǎn)足這些性能的要求,必須要融合多個(gè)節點(diǎn),并且節點(diǎn)之間是相關(guān)之間有交互的。相當于在寫(xiě) mysql 的時(shí)侯,每個(gè)節點(diǎn)儲存部份數據,也就是分布式存儲的來(lái)歷。存儲一些非結構化數據:靜態(tài)文件、圖片、pdf、小視頻 … 這些也就是分布式文件系統的來(lái)歷。
  集群主要是。分布式中的某個(gè)子任簡(jiǎn)單加機器解決問(wèn)題,對于問(wèn)題本身不做任何分解;分布式處理里必然包含任務(wù)分解與答案歸并務(wù)節點(diǎn),可能由一個(gè)集群來(lái)取代;集群中任一節點(diǎn),都是做一個(gè)完整的任務(wù)。集群和分布式都是由多個(gè)節點(diǎn)組成,。但是集群之間的通訊協(xié)調基本不需要;而分布式各個(gè)節點(diǎn)的通訊協(xié)調必不可少RPC
  將一套系統分拆成不同子系統布署在不同服務(wù)器上(這叫分布式),
  然后布署多個(gè)相同的子系統在不同的服務(wù)器上(這叫集群),部署在不同服務(wù)器上的同一個(gè)子系統應做負載均衡。
  負載均衡集群:一個(gè)集群節點(diǎn)來(lái)接受任務(wù),然后按照其余節點(diǎn)的工作狀態(tài)(CPU,內存等信息)派發(fā)任務(wù)量, 最終實(shí)現完成任務(wù)。
  SOA:業(yè)務(wù)系統分解為多個(gè)組件,讓每位組件都獨立提供離散,自治,可復用的服務(wù)能力,通過(guò)服務(wù)的組合和編排來(lái)實(shí)現下層的業(yè)務(wù)流程
  作用:簡(jiǎn)化維護,降低整體風(fēng)險,伸縮靈活
  微服務(wù):架構設計概念,各服務(wù)間隔離(分布式也是隔離),自治(分布式依賴(lài)整體組合)其它特點(diǎn)(單一職責,邊界,異步通信,獨立布署)是分布式概念的跟嚴格執行SOA到微服務(wù)構架的演化過(guò)程 作用:各服務(wù)可獨立應用,組合服務(wù)也可系統應用。SpringClond就是太精典的微服務(wù)框架。
  具體的推行方案
  1.站點(diǎn)層擴充:Nginx 方向代理,高并發(fā)系統,一個(gè) Tomcat 帶不上去,就找十個(gè) Tomcat 去帶
  
  2.服務(wù)層擴充:通過(guò) RPC 框架實(shí)現遠程調用,Dubbo、Spring Boot/Spring Cloud,將業(yè)務(wù)邏輯分拆到不同的 RPC Client,各自完成不同的業(yè)務(wù),如果個(gè)別業(yè)務(wù)的并發(fā)量很大,就降低新的 RPC Client,理論上實(shí)現無(wú)限高并發(fā)。
  3.數據層擴充:一臺數據庫拆成多臺,主從復制、讀寫(xiě)分離、分表分庫。
  ** 進(jìn)程和線(xiàn)程**
  進(jìn)程就是計算機正在運行的一個(gè)獨立的應用程序,進(jìn)程是一個(gè)動(dòng)態(tài)的概念,必須是運行狀態(tài),如果一個(gè)應用程序沒(méi)有啟動(dòng),那就不是進(jìn)程。
  線(xiàn)程就是組成進(jìn)程的基本單位,可以完成特定的功能,一個(gè)進(jìn)程是由一個(gè)或多個(gè)線(xiàn)程組成。
  進(jìn)程和線(xiàn)程的區別在于運行時(shí)是否擁有獨立的顯存空間,每個(gè)進(jìn)程所擁有的空間都是獨立的,互不干擾,多個(gè)線(xiàn)程是共享內存空間的,但是每位線(xiàn)程的執行是互相獨立。
  線(xiàn)程必須依賴(lài)于進(jìn)程能夠執行,單獨線(xiàn)程是難以執行的,由進(jìn)程來(lái)控制多個(gè)線(xiàn)程的執行。
  Java 默認有幾個(gè)線(xiàn)程?
public class OnlyMain {
public static void main(String args) {
//虛擬機線(xiàn)程管理的接口
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
ThreadInfo threadInfos =
threadMXBean.dumpAllThreads(false, false);
for(ThreadInfo threadInfo:threadInfos) {
System.out.println("["+threadInfo.getThreadId()+"]"+" "
+threadInfo.getThreadName());
}
}
}
  Java 默認有兩個(gè)線(xiàn)程:Main 和 GC
  多線(xiàn)程實(shí)現方法
  繼承 Thread
  實(shí)現 Runnable
  實(shí)現 Callable
  重點(diǎn):Thread 是線(xiàn)程對象,Runnable 是任務(wù),一線(xiàn)程啟動(dòng)的時(shí)侯一定是對象。
  
```java
package com.southwind.demo;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test {
public static void main(String args) {
MyCallable myCallable = new MyCallable();
FutureTask futureTask = new FutureTask(myCallable);
Thread thread = new Thread(futureTask);
thread.start();
//獲取Callable的返回值
try {
System.out.println(futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class MyCallable implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println("callable");
return "hello";
}
}
  Runnable對象是Thread構造函數的參數,而Callable對象是FutureTask構造函數的參數,利用FutureTask這個(gè)對象,構建出最后的線(xiàn)程Thread。
  Runable和Thread承繼以后的時(shí)侯,都須要重畫(huà)run技巧。而Callable對象,重寫(xiě)的是call方式。
  Callable 與 Runnable 的區別:
  Callable 的 call 方法有返回值,Runnable 的 run 方法沒(méi)有返回值。
  Callable 的 call 方法可以?huà)伋霎惓?,Runnable 的 run 方法不能拋出異常。
  在外部通過(guò) FutureTask 的 get 方法異步獲取執行結果,FutureTask 是一個(gè)可以控制的異步任務(wù),是對 Runnable 實(shí)現的一種承繼和擴充。
  get 方法可能會(huì )形成阻塞,一般置于代碼的最后。Callable 有緩存。
  線(xiàn)程狀態(tài)
  
  線(xiàn)程只有6種狀態(tài)。整個(gè)生命周期就是這幾種狀態(tài)的切換。
  run()和start() :run方式就是普通對象的普通方式,只有調用了start()后,Java就會(huì )將線(xiàn)程對象和操作系統中實(shí)際的線(xiàn)程進(jìn)行映射,再來(lái)執行run技巧。
  yield() :Thread.yield(),讓出cpu的執行權,將線(xiàn)程從運行轉入可運行狀態(tài),但是下個(gè)時(shí)間片,該線(xiàn)程仍然有可能被再度選中運行 。
  線(xiàn)程的優(yōu)先級 取值為1~10,缺省為5,最高10最低1,但線(xiàn)程的優(yōu)先級不可靠,只是一個(gè)大幾率執行而已,不建議作為線(xiàn)程開(kāi)發(fā)時(shí)侯
  守護線(xiàn)程:和主線(xiàn)程共死,finally不能保證一定執行
  synchronized 用法
  修飾實(shí)例方式,對當前實(shí)例對象this加鎖
public class SynchronizedDemo {

public synchronized void methodOne() {
.....
}
}
  修飾靜態(tài)方式,對當前類(lèi)的Class對象加鎖
public class SynchronizedDemo {
public static synchronized void methodTwo() {
......
}
}
  修飾代碼塊,指定加鎖對象,對給定對象加鎖
public class SynchronizedDemo {
public void methodThree() {
// 對當前實(shí)例對象this加鎖
synchronized (this) {
}
}
public void methodFour() {
// 對class對象加鎖
synchronized (SynchronizedDemo.class) {
....
}
}
}
  volatile
  volatile適合于只有一個(gè)線(xiàn)程寫(xiě),多個(gè)線(xiàn)程讀的場(chǎng)景,因為它只能確??梢?jiàn)性。
  java編程語(yǔ)言容許線(xiàn)程訪(fǎng)問(wèn)共享變量,為了確保共享變量能被確切和一致的更新,線(xiàn)程應當確保通過(guò)排他鎖單獨獲得這個(gè)變量。Java語(yǔ)言提供了volatile,在個(gè)別情況下比鎖愈加便捷。如果一個(gè)數組被申明成volatile,java線(xiàn)程顯存模型確保所有線(xiàn)程聽(tīng)到這個(gè)變量的值是一致的。
  這句話(huà)的涵義有兩層.
  volatile 的寫(xiě)操作, 需要將線(xiàn)程本地顯存值,立馬刷新到 主顯存的共享變量中.
  volatile 的讀操作, 需要從主顯存的共享變量中讀取,更新本地內存變量的值.
  由此引出 volatile 的顯存語(yǔ)義.
  當寫(xiě)一個(gè)volatile變量時(shí),JMM會(huì )把該線(xiàn)程對應的本地顯存中的共享變量值刷新到主顯存.
  當讀一個(gè)volatile變量時(shí),JMM會(huì )把該線(xiàn)程對應的本地顯存置為無(wú)效。線(xiàn)程接下來(lái)將從主顯存中讀取共享變量,并更新本地顯存的值.
  PS :本來(lái)在JVM中有共享變量縣以及技巧的??h,棧區里有共享縣變量的高速緩存的,一般方式縣直接用高速緩存縣數據來(lái)運算。
  volatile 的特點(diǎn)
  可見(jiàn)性 : 對一個(gè)volatile的變量的讀,總是能看到任意線(xiàn)程對這個(gè)變量最后的寫(xiě)入
  互斥性 : 同一時(shí)刻只容許一個(gè)線(xiàn)程對變量進(jìn)行操作.(互斥鎖的特性)
  不具有原子性:復合操作不具有(如inc++ 等價(jià)inc= inc+ 1)
  敲黑板,劃重點(diǎn),volatitle不具有原子性的重點(diǎn)
  假如某個(gè)時(shí)刻變量inc的值為10,線(xiàn)程1對變量進(jìn)行自增操作,線(xiàn)程1先讀取了變量inc的原始值,然后線(xiàn)程1被阻塞了;
  然后線(xiàn)程2對變量進(jìn)行自增操作,線(xiàn)程2也去讀取變量inc的原始值,由于線(xiàn)程1只是對變量inc進(jìn)行讀取操作,而沒(méi)有對變量進(jìn)行更改操作,所以不會(huì )造成線(xiàn)程2的工作顯存中緩存變量inc的緩存行無(wú)效,也不會(huì )造成尋址中的值刷新,所以線(xiàn)程2會(huì )直接去尋址讀取inc的值,發(fā)現inc的值時(shí)10,然后進(jìn)行加1操作,并把11寫(xiě)入工作顯存,最后寫(xiě)入尋址。
  然后線(xiàn)程1接著(zhù)進(jìn)行加1操作,由于早已讀取了inc的值(inc++,包括3個(gè)操作python 多線(xiàn)程網(wǎng)絡(luò )爬蟲(chóng),1.讀取inc的值,2.進(jìn)行加1操作,3.寫(xiě)入新的值),注意此時(shí)在線(xiàn)程1的工作顯存中inc的值依舊為10,所以線(xiàn)程1對inc進(jìn)行加1操作后inc的值為11,然后將11寫(xiě)入工作顯存,最后寫(xiě)入尋址。
  那么兩個(gè)線(xiàn)程分別進(jìn)行了一次自增操作后,inc只降低了1。根源就在這里,自增操作不是原子性操作,而且volatile也難以保證對變量的任何操作都是原子性的。
  解決方案:可以通過(guò)synchronized或lock,進(jìn)行加鎖,來(lái)保證操作的原子性。也可以通過(guò)使用AtomicInteger
  什么是JMM
  JMM(java memory model)決定一個(gè)線(xiàn)程對共享變量的寫(xiě)入何時(shí)對另一個(gè)線(xiàn)程可見(jiàn),JMM定義了線(xiàn)程和主內存之間的具象關(guān)系:共享變量?jì)Υ嬖谥黠@存(Main Memory)中,每個(gè)線(xiàn)程都有一個(gè)私有的本地顯存(Local Memory),本地顯存保存了被該線(xiàn)程使用到的主顯存的副本拷貝,線(xiàn)程對變量的所有操作都必須在工作顯存中進(jìn)行,而不能直接讀寫(xiě)主顯存中的變量。
  
  聲明變量為volatile后 方法縣中的數據本地緩存就失效了,每次都要在主顯存中拿。
  ThreadLocal
  線(xiàn)程局部變量。進(jìn)來(lái)類(lèi)型簡(jiǎn)單點(diǎn)哦,可以理解為是個(gè)map,比如類(lèi)型 Map<Thread,Integer>python 多線(xiàn)程網(wǎng)絡(luò )爬蟲(chóng),跟Python中的線(xiàn)程局部變量類(lèi)似。
public class UseThreadLocal {
//可以理解為 一個(gè)map,類(lèi)型 Map<Thread,Integer>
static ThreadLocal<Integer> threadLaocl = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 1;
}
};
/**
* 運行3個(gè)線(xiàn)程
*/
public void StartThreadArray() {
Thread runs = new Thread[3];
for (int i = 0; i < runs.length; i++) {
runs = new Thread(new TestThread(i));
}
for (int i = 0; i < runs.length; i++) {
runs[i].start();
}
}
/**
* 類(lèi)說(shuō)明:測試線(xiàn)程,線(xiàn)程的工作是將ThreadLocal變量的值變化,并寫(xiě)回,看看線(xiàn)程之間是否會(huì )互相影響
*/
public static class TestThread implements Runnable {
int id;
public TestThread(int id) {
this.id = id;
}
public void run() {
System.out.println(Thread.currentThread().getName() + ":start");
Integer s = threadLaocl.get();//獲得變量的值
s = s + id;
threadLaocl.set(s);
System.out.println(Thread.currentThread().getName() + ":" + threadLaocl.get());
//threadLaocl.remove();
}
}
public static void main(String args) {
UseThreadLocal test = new UseThreadLocal();
test.StartThreadArray();
}
}
  wait notify
  wait是指在一個(gè)早已步入了同步鎖的線(xiàn)程內,讓自己暫時(shí)讓出同步鎖,以便其他正在等待此鎖的線(xiàn)程可以得到同步鎖并運行,只有其他線(xiàn)程調用了notify方式(notify并不釋放鎖,只是告訴調用過(guò)wait方式的線(xiàn)程可以去參與獲得鎖的競爭了,但不是馬上得到鎖,因為鎖還在他人手里,別人還沒(méi)釋放),調用wait方式的一個(gè)或多個(gè)線(xiàn)程都會(huì )解除wait狀態(tài),重新參與競爭對象鎖,程序假如可以再度得到鎖,就可以繼續向上運行。
  wait()、notify()和notifyAll()方法是本地方式,并且為final方式,無(wú)法被重畫(huà)。
  當前線(xiàn)程必須擁有此對象的monitor(即鎖),才能調用某個(gè)對象的wait()方法能使當前線(xiàn)程阻塞。(這種阻塞是通過(guò)提早釋放synchronized鎖,重新去懇求鎖造成的阻塞,這種懇求必須有其他線(xiàn)程通過(guò)notify()或者notifyAll()喚醒重新競爭獲得鎖)
  調用某個(gè)對象的notify()方法才能喚起一個(gè)正在等待這個(gè)對象的monitor的線(xiàn)程,如果有多個(gè)線(xiàn)程都在等待這個(gè)對象的monitor,則只能喚起其中一個(gè)線(xiàn)程; (notify()或者notifyAll()方法并不是真正釋放鎖,必須等到synchronized方式或則語(yǔ)法塊執行完才真正釋放鎖)
  調用notifyAll()方法才能喚起所有正在等待這個(gè)對象的monitor的線(xiàn)程,喚醒的線(xiàn)程獲得鎖的機率是隨機的,取決于cpu調度
  調用yield() 、sleep()、wait()、notify()等方式對鎖有何影響?
  線(xiàn)程在執行yield()以后,持有的鎖是不釋放的,操作系統一直可能選擇到該進(jìn)程。不釋放鎖
  sleep()方法被調用之后,持有的鎖是不釋放的,休眠期間操作系統不會(huì )再執行該進(jìn)程。不釋放鎖
  調動(dòng)方式之前,必須要持有鎖。調用了wait()方法之后,鎖都會(huì )被釋放,當wait方式返回的時(shí)侯,線(xiàn)程會(huì )重新持有鎖 .
  wait方式是面對對象的,表示當前的對象會(huì )步入阻塞,在notify/all調用以后,會(huì )重新步入就緒狀態(tài)。
  調動(dòng)方式之前,必須要持有鎖,調用notify()方法本身不會(huì )釋放鎖的,只是告訴調用過(guò)wait方式的線(xiàn)程可以去參與獲得鎖的競爭了.[/i] 查看全部
  
  一言以蔽之:Java 并發(fā)編程的目的就是充分利用計算機的資源,把計算機的性能發(fā)揮到最大
  
  什么是高并發(fā)
  并發(fā) concurrency 和并行 parallelism 的區別
  并發(fā)是指多個(gè)線(xiàn)程操作同一個(gè)資源,不是同時(shí)操作,而是交替操作,單核 CPU,只不過(guò)由于速率很快,看起來(lái)是同時(shí)執行(張三、李四,共用一口鍋煮飯,交替執行),通過(guò)時(shí)間片輪轉機制RR調度實(shí)現并發(fā)。
  速度很快,看起來(lái)象是并行。
  并行才是真正的同時(shí)執行,多核 CPU,每個(gè)線(xiàn)程使用一個(gè)獨立的 CPU 的資源來(lái)運行。(張三、李四,一人一口鍋,一起燉肉)
  并發(fā)編程是指使系統容許多個(gè)任務(wù)在重疊的時(shí)間段內執行的設計結構。
  高并發(fā)我們設計的程序,可以支持海量任務(wù)的同時(shí)執行(任務(wù)的執行在時(shí)間段上有重疊的情況)
  QPS:每秒響應的懇求數,QPS 并不是并發(fā)數。
  吞吐量:?jiǎn)挝粫r(shí)間內處理的懇求數,QPS 和并發(fā)數決定。
  平均響應時(shí)間:系統對一個(gè)懇求做出響應的平均時(shí)間,QPS = 并發(fā)數/平均響應時(shí)間
  并發(fā)用戶(hù)數:系統可以承載的最大用戶(hù)數目。
  高并發(fā)編程優(yōu)劣
  利:充分利用cpu的資源、加快用戶(hù)響應的時(shí)間,程序模塊化,異步化
  弊:線(xiàn)程共享資源,存在沖突。容易造成死鎖。 啟用太多的線(xiàn)程,就有扳倒機器的可能。
  互聯(lián)網(wǎng)項目構架中,如何提升系統的并發(fā)能力?
  垂直擴充
  水平擴充
  垂直擴充
  提升單機的處理能力
  1、增強單機的硬件性能:增加 CPU 的核數,硬盤(pán)擴容,內存升級。
  2、提升系統的構架性能:使用 Cache 來(lái)提升效率,異步懇求降低單個(gè)服務(wù)的吞吐量,使用 NoSQL 來(lái)提高數據的訪(fǎng)問(wèn)性能。
  水平擴充
  集群、分布式都是水平擴充的方案
  集群:多個(gè)人做同一件事情(3 個(gè)面點(diǎn)師同時(shí)燉肉)
  分布式:把一件復雜的事情,拆分成幾個(gè)簡(jiǎn)單的步驟,分別找不同的人去完成 (1 洗菜、2 切菜、3 炒菜)
  
  
  分布式是指多個(gè)系統協(xié)同合作完成一個(gè)特定任務(wù)的系統。分布式解決問(wèn)題,把所有解決中心化管理的任務(wù)疊加到一個(gè)節點(diǎn)處理,太慢了。把一個(gè)業(yè)務(wù)分拆為多個(gè)子業(yè)務(wù)(當某個(gè)子業(yè)務(wù)訪(fǎng)問(wèn)量突增時(shí),增加該子任務(wù)的節點(diǎn)數即可),部署在多個(gè)服務(wù)器上 ,分布式的主要工作是分解任務(wù),將職能拆解。
  集群主要的使用場(chǎng)景是為了分擔懇求的壓力,同一個(gè)業(yè)務(wù),部署在多個(gè)服務(wù)器上 ,也就是在幾個(gè)服務(wù)器上布署來(lái)==相同的應用程序,==分擔客戶(hù)端懇求。當壓力進(jìn)一步減小的時(shí)侯,可能在須要儲存的部份,mysql 無(wú)法面對好多的寫(xiě)壓力。因為在 mysql 做成集群以后,主要的寫(xiě)壓力還是在 master 的機器里面,其他 slave 機器難以分擔寫(xiě)壓力,從而這個(gè)時(shí)侯,也就引下來(lái)分布式。分布式的主要應用場(chǎng)景是單臺機器早已未能滿(mǎn)足這些性能的要求,必須要融合多個(gè)節點(diǎn),并且節點(diǎn)之間是相關(guān)之間有交互的。相當于在寫(xiě) mysql 的時(shí)侯,每個(gè)節點(diǎn)儲存部份數據,也就是分布式存儲的來(lái)歷。存儲一些非結構化數據:靜態(tài)文件、圖片、pdf、小視頻 … 這些也就是分布式文件系統的來(lái)歷。
  集群主要是。分布式中的某個(gè)子任簡(jiǎn)單加機器解決問(wèn)題,對于問(wèn)題本身不做任何分解;分布式處理里必然包含任務(wù)分解與答案歸并務(wù)節點(diǎn),可能由一個(gè)集群來(lái)取代;集群中任一節點(diǎn),都是做一個(gè)完整的任務(wù)。集群和分布式都是由多個(gè)節點(diǎn)組成,。但是集群之間的通訊協(xié)調基本不需要;而分布式各個(gè)節點(diǎn)的通訊協(xié)調必不可少RPC
  將一套系統分拆成不同子系統布署在不同服務(wù)器上(這叫分布式),
  然后布署多個(gè)相同的子系統在不同的服務(wù)器上(這叫集群),部署在不同服務(wù)器上的同一個(gè)子系統應做負載均衡。
  負載均衡集群:一個(gè)集群節點(diǎn)來(lái)接受任務(wù),然后按照其余節點(diǎn)的工作狀態(tài)(CPU,內存等信息)派發(fā)任務(wù)量, 最終實(shí)現完成任務(wù)。
  SOA:業(yè)務(wù)系統分解為多個(gè)組件,讓每位組件都獨立提供離散,自治,可復用的服務(wù)能力,通過(guò)服務(wù)的組合和編排來(lái)實(shí)現下層的業(yè)務(wù)流程
  作用:簡(jiǎn)化維護,降低整體風(fēng)險,伸縮靈活
  微服務(wù):架構設計概念,各服務(wù)間隔離(分布式也是隔離),自治(分布式依賴(lài)整體組合)其它特點(diǎn)(單一職責,邊界,異步通信,獨立布署)是分布式概念的跟嚴格執行SOA到微服務(wù)構架的演化過(guò)程 作用:各服務(wù)可獨立應用,組合服務(wù)也可系統應用。SpringClond就是太精典的微服務(wù)框架。
  具體的推行方案
  1.站點(diǎn)層擴充:Nginx 方向代理,高并發(fā)系統,一個(gè) Tomcat 帶不上去,就找十個(gè) Tomcat 去帶
  
  2.服務(wù)層擴充:通過(guò) RPC 框架實(shí)現遠程調用,Dubbo、Spring Boot/Spring Cloud,將業(yè)務(wù)邏輯分拆到不同的 RPC Client,各自完成不同的業(yè)務(wù),如果個(gè)別業(yè)務(wù)的并發(fā)量很大,就降低新的 RPC Client,理論上實(shí)現無(wú)限高并發(fā)。
  3.數據層擴充:一臺數據庫拆成多臺,主從復制、讀寫(xiě)分離、分表分庫。
  ** 進(jìn)程和線(xiàn)程**
  進(jìn)程就是計算機正在運行的一個(gè)獨立的應用程序,進(jìn)程是一個(gè)動(dòng)態(tài)的概念,必須是運行狀態(tài),如果一個(gè)應用程序沒(méi)有啟動(dòng),那就不是進(jìn)程。
  線(xiàn)程就是組成進(jìn)程的基本單位,可以完成特定的功能,一個(gè)進(jìn)程是由一個(gè)或多個(gè)線(xiàn)程組成。
  進(jìn)程和線(xiàn)程的區別在于運行時(shí)是否擁有獨立的顯存空間,每個(gè)進(jìn)程所擁有的空間都是獨立的,互不干擾,多個(gè)線(xiàn)程是共享內存空間的,但是每位線(xiàn)程的執行是互相獨立。
  線(xiàn)程必須依賴(lài)于進(jìn)程能夠執行,單獨線(xiàn)程是難以執行的,由進(jìn)程來(lái)控制多個(gè)線(xiàn)程的執行。
  Java 默認有幾個(gè)線(xiàn)程?
public class OnlyMain {
public static void main(String args) {
//虛擬機線(xiàn)程管理的接口
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
ThreadInfo threadInfos =
threadMXBean.dumpAllThreads(false, false);
for(ThreadInfo threadInfo:threadInfos) {
System.out.println("["+threadInfo.getThreadId()+"]"+" "
+threadInfo.getThreadName());
}
}
}
  Java 默認有兩個(gè)線(xiàn)程:Main 和 GC
  多線(xiàn)程實(shí)現方法
  繼承 Thread
  實(shí)現 Runnable
  實(shí)現 Callable
  重點(diǎn):Thread 是線(xiàn)程對象,Runnable 是任務(wù),一線(xiàn)程啟動(dòng)的時(shí)侯一定是對象。
  
```java
package com.southwind.demo;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test {
public static void main(String args) {
MyCallable myCallable = new MyCallable();
FutureTask futureTask = new FutureTask(myCallable);
Thread thread = new Thread(futureTask);
thread.start();
//獲取Callable的返回值
try {
System.out.println(futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class MyCallable implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println("callable");
return "hello";
}
}
  Runnable對象是Thread構造函數的參數,而Callable對象是FutureTask構造函數的參數,利用FutureTask這個(gè)對象,構建出最后的線(xiàn)程Thread。
  Runable和Thread承繼以后的時(shí)侯,都須要重畫(huà)run技巧。而Callable對象,重寫(xiě)的是call方式。
  Callable 與 Runnable 的區別:
  Callable 的 call 方法有返回值,Runnable 的 run 方法沒(méi)有返回值。
  Callable 的 call 方法可以?huà)伋霎惓?,Runnable 的 run 方法不能拋出異常。
  在外部通過(guò) FutureTask 的 get 方法異步獲取執行結果,FutureTask 是一個(gè)可以控制的異步任務(wù),是對 Runnable 實(shí)現的一種承繼和擴充。
  get 方法可能會(huì )形成阻塞,一般置于代碼的最后。Callable 有緩存。
  線(xiàn)程狀態(tài)
  
  線(xiàn)程只有6種狀態(tài)。整個(gè)生命周期就是這幾種狀態(tài)的切換。
  run()和start() :run方式就是普通對象的普通方式,只有調用了start()后,Java就會(huì )將線(xiàn)程對象和操作系統中實(shí)際的線(xiàn)程進(jìn)行映射,再來(lái)執行run技巧。
  yield() :Thread.yield(),讓出cpu的執行權,將線(xiàn)程從運行轉入可運行狀態(tài),但是下個(gè)時(shí)間片,該線(xiàn)程仍然有可能被再度選中運行 。
  線(xiàn)程的優(yōu)先級 取值為1~10,缺省為5,最高10最低1,但線(xiàn)程的優(yōu)先級不可靠,只是一個(gè)大幾率執行而已,不建議作為線(xiàn)程開(kāi)發(fā)時(shí)侯
  守護線(xiàn)程:和主線(xiàn)程共死,finally不能保證一定執行
  synchronized 用法
  修飾實(shí)例方式,對當前實(shí)例對象this加鎖
public class SynchronizedDemo {

public synchronized void methodOne() {
.....
}
}
  修飾靜態(tài)方式,對當前類(lèi)的Class對象加鎖
public class SynchronizedDemo {
public static synchronized void methodTwo() {
......
}
}
  修飾代碼塊,指定加鎖對象,對給定對象加鎖
public class SynchronizedDemo {
public void methodThree() {
// 對當前實(shí)例對象this加鎖
synchronized (this) {
}
}
public void methodFour() {
// 對class對象加鎖
synchronized (SynchronizedDemo.class) {
....
}
}
}
  volatile
  volatile適合于只有一個(gè)線(xiàn)程寫(xiě),多個(gè)線(xiàn)程讀的場(chǎng)景,因為它只能確??梢?jiàn)性。
  java編程語(yǔ)言容許線(xiàn)程訪(fǎng)問(wèn)共享變量,為了確保共享變量能被確切和一致的更新,線(xiàn)程應當確保通過(guò)排他鎖單獨獲得這個(gè)變量。Java語(yǔ)言提供了volatile,在個(gè)別情況下比鎖愈加便捷。如果一個(gè)數組被申明成volatile,java線(xiàn)程顯存模型確保所有線(xiàn)程聽(tīng)到這個(gè)變量的值是一致的。
  這句話(huà)的涵義有兩層.
  volatile 的寫(xiě)操作, 需要將線(xiàn)程本地顯存值,立馬刷新到 主顯存的共享變量中.
  volatile 的讀操作, 需要從主顯存的共享變量中讀取,更新本地內存變量的值.
  由此引出 volatile 的顯存語(yǔ)義.
  當寫(xiě)一個(gè)volatile變量時(shí),JMM會(huì )把該線(xiàn)程對應的本地顯存中的共享變量值刷新到主顯存.
  當讀一個(gè)volatile變量時(shí),JMM會(huì )把該線(xiàn)程對應的本地顯存置為無(wú)效。線(xiàn)程接下來(lái)將從主顯存中讀取共享變量,并更新本地顯存的值.
  PS :本來(lái)在JVM中有共享變量縣以及技巧的??h,棧區里有共享縣變量的高速緩存的,一般方式縣直接用高速緩存縣數據來(lái)運算。
  volatile 的特點(diǎn)
  可見(jiàn)性 : 對一個(gè)volatile的變量的讀,總是能看到任意線(xiàn)程對這個(gè)變量最后的寫(xiě)入
  互斥性 : 同一時(shí)刻只容許一個(gè)線(xiàn)程對變量進(jìn)行操作.(互斥鎖的特性)
  不具有原子性:復合操作不具有(如inc++ 等價(jià)inc= inc+ 1)
  敲黑板,劃重點(diǎn),volatitle不具有原子性的重點(diǎn)
  假如某個(gè)時(shí)刻變量inc的值為10,線(xiàn)程1對變量進(jìn)行自增操作,線(xiàn)程1先讀取了變量inc的原始值,然后線(xiàn)程1被阻塞了;
  然后線(xiàn)程2對變量進(jìn)行自增操作,線(xiàn)程2也去讀取變量inc的原始值,由于線(xiàn)程1只是對變量inc進(jìn)行讀取操作,而沒(méi)有對變量進(jìn)行更改操作,所以不會(huì )造成線(xiàn)程2的工作顯存中緩存變量inc的緩存行無(wú)效,也不會(huì )造成尋址中的值刷新,所以線(xiàn)程2會(huì )直接去尋址讀取inc的值,發(fā)現inc的值時(shí)10,然后進(jìn)行加1操作,并把11寫(xiě)入工作顯存,最后寫(xiě)入尋址。
  然后線(xiàn)程1接著(zhù)進(jìn)行加1操作,由于早已讀取了inc的值(inc++,包括3個(gè)操作python 多線(xiàn)程網(wǎng)絡(luò )爬蟲(chóng),1.讀取inc的值,2.進(jìn)行加1操作,3.寫(xiě)入新的值),注意此時(shí)在線(xiàn)程1的工作顯存中inc的值依舊為10,所以線(xiàn)程1對inc進(jìn)行加1操作后inc的值為11,然后將11寫(xiě)入工作顯存,最后寫(xiě)入尋址。
  那么兩個(gè)線(xiàn)程分別進(jìn)行了一次自增操作后,inc只降低了1。根源就在這里,自增操作不是原子性操作,而且volatile也難以保證對變量的任何操作都是原子性的。
  解決方案:可以通過(guò)synchronized或lock,進(jìn)行加鎖,來(lái)保證操作的原子性。也可以通過(guò)使用AtomicInteger
  什么是JMM
  JMM(java memory model)決定一個(gè)線(xiàn)程對共享變量的寫(xiě)入何時(shí)對另一個(gè)線(xiàn)程可見(jiàn),JMM定義了線(xiàn)程和主內存之間的具象關(guān)系:共享變量?jì)Υ嬖谥黠@存(Main Memory)中,每個(gè)線(xiàn)程都有一個(gè)私有的本地顯存(Local Memory),本地顯存保存了被該線(xiàn)程使用到的主顯存的副本拷貝,線(xiàn)程對變量的所有操作都必須在工作顯存中進(jìn)行,而不能直接讀寫(xiě)主顯存中的變量。
  
  聲明變量為volatile后 方法縣中的數據本地緩存就失效了,每次都要在主顯存中拿。
  ThreadLocal
  線(xiàn)程局部變量。進(jìn)來(lái)類(lèi)型簡(jiǎn)單點(diǎn)哦,可以理解為是個(gè)map,比如類(lèi)型 Map<Thread,Integer>python 多線(xiàn)程網(wǎng)絡(luò )爬蟲(chóng),跟Python中的線(xiàn)程局部變量類(lèi)似。
public class UseThreadLocal {
//可以理解為 一個(gè)map,類(lèi)型 Map<Thread,Integer>
static ThreadLocal<Integer> threadLaocl = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 1;
}
};
/**
* 運行3個(gè)線(xiàn)程
*/
public void StartThreadArray() {
Thread runs = new Thread[3];
for (int i = 0; i < runs.length; i++) {
runs = new Thread(new TestThread(i));
}
for (int i = 0; i < runs.length; i++) {
runs[i].start();
}
}
/**
* 類(lèi)說(shuō)明:測試線(xiàn)程,線(xiàn)程的工作是將ThreadLocal變量的值變化,并寫(xiě)回,看看線(xiàn)程之間是否會(huì )互相影響
*/
public static class TestThread implements Runnable {
int id;
public TestThread(int id) {
this.id = id;
}
public void run() {
System.out.println(Thread.currentThread().getName() + ":start");
Integer s = threadLaocl.get();//獲得變量的值
s = s + id;
threadLaocl.set(s);
System.out.println(Thread.currentThread().getName() + ":" + threadLaocl.get());
//threadLaocl.remove();
}
}
public static void main(String args) {
UseThreadLocal test = new UseThreadLocal();
test.StartThreadArray();
}
}
  wait notify
  wait是指在一個(gè)早已步入了同步鎖的線(xiàn)程內,讓自己暫時(shí)讓出同步鎖,以便其他正在等待此鎖的線(xiàn)程可以得到同步鎖并運行,只有其他線(xiàn)程調用了notify方式(notify并不釋放鎖,只是告訴調用過(guò)wait方式的線(xiàn)程可以去參與獲得鎖的競爭了,但不是馬上得到鎖,因為鎖還在他人手里,別人還沒(méi)釋放),調用wait方式的一個(gè)或多個(gè)線(xiàn)程都會(huì )解除wait狀態(tài),重新參與競爭對象鎖,程序假如可以再度得到鎖,就可以繼續向上運行。
  wait()、notify()和notifyAll()方法是本地方式,并且為final方式,無(wú)法被重畫(huà)。
  當前線(xiàn)程必須擁有此對象的monitor(即鎖),才能調用某個(gè)對象的wait()方法能使當前線(xiàn)程阻塞。(這種阻塞是通過(guò)提早釋放synchronized鎖,重新去懇求鎖造成的阻塞,這種懇求必須有其他線(xiàn)程通過(guò)notify()或者notifyAll()喚醒重新競爭獲得鎖)
  調用某個(gè)對象的notify()方法才能喚起一個(gè)正在等待這個(gè)對象的monitor的線(xiàn)程,如果有多個(gè)線(xiàn)程都在等待這個(gè)對象的monitor,則只能喚起其中一個(gè)線(xiàn)程; (notify()或者notifyAll()方法并不是真正釋放鎖,必須等到synchronized方式或則語(yǔ)法塊執行完才真正釋放鎖)
  調用notifyAll()方法才能喚起所有正在等待這個(gè)對象的monitor的線(xiàn)程,喚醒的線(xiàn)程獲得鎖的機率是隨機的,取決于cpu調度
  調用yield() 、sleep()、wait()、notify()等方式對鎖有何影響?
  線(xiàn)程在執行yield()以后,持有的鎖是不釋放的,操作系統一直可能選擇到該進(jìn)程。不釋放鎖
  sleep()方法被調用之后,持有的鎖是不釋放的,休眠期間操作系統不會(huì )再執行該進(jìn)程。不釋放鎖
  調動(dòng)方式之前,必須要持有鎖。調用了wait()方法之后,鎖都會(huì )被釋放,當wait方式返回的時(shí)侯,線(xiàn)程會(huì )重新持有鎖 .
  wait方式是面對對象的,表示當前的對象會(huì )步入阻塞,在notify/all調用以后,會(huì )重新步入就緒狀態(tài)。
  調動(dòng)方式之前,必須要持有鎖,調用notify()方法本身不會(huì )釋放鎖的,只是告訴調用過(guò)wait方式的線(xiàn)程可以去參與獲得鎖的競爭了.
[/i]

java并發(fā)編程 線(xiàn)程基礎/線(xiàn)程之間的共享和協(xié)作

采集交流 ? 優(yōu)采云 發(fā)表了文章 ? 0 個(gè)評論 ? 339 次瀏覽 ? 2020-04-05 11:36 ? 來(lái)自相關(guān)話(huà)題

  
  一言以蔽之:Java 并發(fā)編程的目的就是充分利用計算機的資源,把計算機的性能發(fā)揮到最大
  
  什么是高并發(fā)
  并發(fā) concurrency 和并行 parallelism 的區別
  并發(fā)是指多個(gè)線(xiàn)程操作同一個(gè)資源,不是同時(shí)操作,而是交替操作,單核 CPU,只不過(guò)由于速率很快,看起來(lái)是同時(shí)執行(張三、李四,共用一口鍋煮飯,交替執行),通過(guò)時(shí)間片輪轉機制RR調度實(shí)現并發(fā)。
  速度很快,看起來(lái)象是并行。
  并行才是真正的同時(shí)執行,多核 CPU,每個(gè)線(xiàn)程使用一個(gè)獨立的 CPU 的資源來(lái)運行。(張三、李四,一人一口鍋,一起燉肉)
  并發(fā)編程是指使系統容許多個(gè)任務(wù)在重疊的時(shí)間段內執行的設計結構。
  高并發(fā)我們設計的程序,可以支持海量任務(wù)的同時(shí)執行(任務(wù)的執行在時(shí)間段上有重疊的情況)
  QPS:每秒響應的懇求數,QPS 并不是并發(fā)數。
  吞吐量:?jiǎn)挝粫r(shí)間內處理的懇求數,QPS 和并發(fā)數決定。
  平均響應時(shí)間:系統對一個(gè)懇求做出響應的平均時(shí)間,QPS = 并發(fā)數/平均響應時(shí)間
  并發(fā)用戶(hù)數:系統可以承載的最大用戶(hù)數目。
  高并發(fā)編程優(yōu)劣
  利:充分利用cpu的資源、加快用戶(hù)響應的時(shí)間,程序模塊化,異步化
  弊:線(xiàn)程共享資源,存在沖突。容易造成死鎖。 啟用太多的線(xiàn)程,就有扳倒機器的可能。
  互聯(lián)網(wǎng)項目構架中,如何提升系統的并發(fā)能力?
  垂直擴充
  水平擴充
  垂直擴充
  提升單機的處理能力
  1、增強單機的硬件性能:增加 CPU 的核數,硬盤(pán)擴容,內存升級。
  2、提升系統的構架性能:使用 Cache 來(lái)提升效率,異步懇求降低單個(gè)服務(wù)的吞吐量,使用 NoSQL 來(lái)提高數據的訪(fǎng)問(wèn)性能。
  水平擴充
  集群、分布式都是水平擴充的方案
  集群:多個(gè)人做同一件事情(3 個(gè)面點(diǎn)師同時(shí)燉肉)
  分布式:把一件復雜的事情,拆分成幾個(gè)簡(jiǎn)單的步驟,分別找不同的人去完成 (1 洗菜、2 切菜、3 炒菜)
  
  
  分布式是指多個(gè)系統協(xié)同合作完成一個(gè)特定任務(wù)的系統。分布式解決問(wèn)題,把所有解決中心化管理的任務(wù)疊加到一個(gè)節點(diǎn)處理,太慢了。把一個(gè)業(yè)務(wù)分拆為多個(gè)子業(yè)務(wù)(當某個(gè)子業(yè)務(wù)訪(fǎng)問(wèn)量突增時(shí),增加該子任務(wù)的節點(diǎn)數即可),部署在多個(gè)服務(wù)器上 ,分布式的主要工作是分解任務(wù),將職能拆解。
  集群主要的使用場(chǎng)景是為了分擔懇求的壓力,同一個(gè)業(yè)務(wù),部署在多個(gè)服務(wù)器上 ,也就是在幾個(gè)服務(wù)器上布署來(lái)==相同的應用程序,==分擔客戶(hù)端懇求。當壓力進(jìn)一步減小的時(shí)侯,可能在須要儲存的部份,mysql 無(wú)法面對好多的寫(xiě)壓力。因為在 mysql 做成集群以后,主要的寫(xiě)壓力還是在 master 的機器里面,其他 slave 機器難以分擔寫(xiě)壓力,從而這個(gè)時(shí)侯,也就引下來(lái)分布式。分布式的主要應用場(chǎng)景是單臺機器早已未能滿(mǎn)足這些性能的要求,必須要融合多個(gè)節點(diǎn),并且節點(diǎn)之間是相關(guān)之間有交互的。相當于在寫(xiě) mysql 的時(shí)侯,每個(gè)節點(diǎn)儲存部份數據,也就是分布式存儲的來(lái)歷。存儲一些非結構化數據:靜態(tài)文件、圖片、pdf、小視頻 … 這些也就是分布式文件系統的來(lái)歷。
  集群主要是。分布式中的某個(gè)子任簡(jiǎn)單加機器解決問(wèn)題,對于問(wèn)題本身不做任何分解;分布式處理里必然包含任務(wù)分解與答案歸并務(wù)節點(diǎn),可能由一個(gè)集群來(lái)取代;集群中任一節點(diǎn),都是做一個(gè)完整的任務(wù)。集群和分布式都是由多個(gè)節點(diǎn)組成,。但是集群之間的通訊協(xié)調基本不需要;而分布式各個(gè)節點(diǎn)的通訊協(xié)調必不可少RPC
  將一套系統分拆成不同子系統布署在不同服務(wù)器上(這叫分布式),
  然后布署多個(gè)相同的子系統在不同的服務(wù)器上(這叫集群),部署在不同服務(wù)器上的同一個(gè)子系統應做負載均衡。
  負載均衡集群:一個(gè)集群節點(diǎn)來(lái)接受任務(wù),然后按照其余節點(diǎn)的工作狀態(tài)(CPU,內存等信息)派發(fā)任務(wù)量, 最終實(shí)現完成任務(wù)。
  SOA:業(yè)務(wù)系統分解為多個(gè)組件,讓每位組件都獨立提供離散,自治,可復用的服務(wù)能力,通過(guò)服務(wù)的組合和編排來(lái)實(shí)現下層的業(yè)務(wù)流程
  作用:簡(jiǎn)化維護,降低整體風(fēng)險,伸縮靈活
  微服務(wù):架構設計概念,各服務(wù)間隔離(分布式也是隔離),自治(分布式依賴(lài)整體組合)其它特點(diǎn)(單一職責,邊界,異步通信,獨立布署)是分布式概念的跟嚴格執行SOA到微服務(wù)構架的演化過(guò)程 作用:各服務(wù)可獨立應用,組合服務(wù)也可系統應用。SpringClond就是太精典的微服務(wù)框架。
  具體的推行方案
  1.站點(diǎn)層擴充:Nginx 方向代理,高并發(fā)系統,一個(gè) Tomcat 帶不上去,就找十個(gè) Tomcat 去帶
  
  2.服務(wù)層擴充:通過(guò) RPC 框架實(shí)現遠程調用,Dubbo、Spring Boot/Spring Cloud,將業(yè)務(wù)邏輯分拆到不同的 RPC Client,各自完成不同的業(yè)務(wù),如果個(gè)別業(yè)務(wù)的并發(fā)量很大,就降低新的 RPC Client,理論上實(shí)現無(wú)限高并發(fā)。
  3.數據層擴充:一臺數據庫拆成多臺,主從復制、讀寫(xiě)分離、分表分庫。
  ** 進(jìn)程和線(xiàn)程**
  進(jìn)程就是計算機正在運行的一個(gè)獨立的應用程序,進(jìn)程是一個(gè)動(dòng)態(tài)的概念,必須是運行狀態(tài),如果一個(gè)應用程序沒(méi)有啟動(dòng),那就不是進(jìn)程。
  線(xiàn)程就是組成進(jìn)程的基本單位,可以完成特定的功能,一個(gè)進(jìn)程是由一個(gè)或多個(gè)線(xiàn)程組成。
  進(jìn)程和線(xiàn)程的區別在于運行時(shí)是否擁有獨立的顯存空間,每個(gè)進(jìn)程所擁有的空間都是獨立的,互不干擾,多個(gè)線(xiàn)程是共享內存空間的,但是每位線(xiàn)程的執行是互相獨立。
  線(xiàn)程必須依賴(lài)于進(jìn)程能夠執行,單獨線(xiàn)程是難以執行的,由進(jìn)程來(lái)控制多個(gè)線(xiàn)程的執行。
  Java 默認有幾個(gè)線(xiàn)程?
public class OnlyMain {
public static void main(String args) {
//虛擬機線(xiàn)程管理的接口
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
ThreadInfo threadInfos =
threadMXBean.dumpAllThreads(false, false);
for(ThreadInfo threadInfo:threadInfos) {
System.out.println("["+threadInfo.getThreadId()+"]"+" "
+threadInfo.getThreadName());
}
}
}
  Java 默認有兩個(gè)線(xiàn)程:Main 和 GC
  多線(xiàn)程實(shí)現方法
  繼承 Thread
  實(shí)現 Runnable
  實(shí)現 Callable
  重點(diǎn):Thread 是線(xiàn)程對象,Runnable 是任務(wù),一線(xiàn)程啟動(dòng)的時(shí)侯一定是對象。
  
```java
package com.southwind.demo;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test {
public static void main(String args) {
MyCallable myCallable = new MyCallable();
FutureTask futureTask = new FutureTask(myCallable);
Thread thread = new Thread(futureTask);
thread.start();
//獲取Callable的返回值
try {
System.out.println(futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class MyCallable implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println("callable");
return "hello";
}
}
  Runnable對象是Thread構造函數的參數,而Callable對象是FutureTask構造函數的參數,利用FutureTask這個(gè)對象,構建出最后的線(xiàn)程Thread。
  Runable和Thread承繼以后的時(shí)侯,都須要重畫(huà)run技巧。而Callable對象,重寫(xiě)的是call方式。
  Callable 與 Runnable 的區別:
  Callable 的 call 方法有返回值,Runnable 的 run 方法沒(méi)有返回值。
  Callable 的 call 方法可以?huà)伋霎惓?,Runnable 的 run 方法不能拋出異常。
  在外部通過(guò) FutureTask 的 get 方法異步獲取執行結果,FutureTask 是一個(gè)可以控制的異步任務(wù),是對 Runnable 實(shí)現的一種承繼和擴充。
  get 方法可能會(huì )形成阻塞,一般置于代碼的最后。Callable 有緩存。
  線(xiàn)程狀態(tài)
  
  線(xiàn)程只有6種狀態(tài)。整個(gè)生命周期就是這幾種狀態(tài)的切換。
  run()和start() :run方式就是普通對象的普通方式,只有調用了start()后,Java就會(huì )將線(xiàn)程對象和操作系統中實(shí)際的線(xiàn)程進(jìn)行映射,再來(lái)執行run技巧。
  yield() :Thread.yield(),讓出cpu的執行權,將線(xiàn)程從運行轉入可運行狀態(tài),但是下個(gè)時(shí)間片,該線(xiàn)程仍然有可能被再度選中運行 。
  線(xiàn)程的優(yōu)先級 取值為1~10,缺省為5,最高10最低1,但線(xiàn)程的優(yōu)先級不可靠,只是一個(gè)大幾率執行而已,不建議作為線(xiàn)程開(kāi)發(fā)時(shí)侯
  守護線(xiàn)程:和主線(xiàn)程共死,finally不能保證一定執行
  synchronized 用法
  修飾實(shí)例方式,對當前實(shí)例對象this加鎖
public class SynchronizedDemo {

public synchronized void methodOne() {
.....
}
}
  修飾靜態(tài)方式,對當前類(lèi)的Class對象加鎖
public class SynchronizedDemo {
public static synchronized void methodTwo() {
......
}
}
  修飾代碼塊,指定加鎖對象,對給定對象加鎖
public class SynchronizedDemo {
public void methodThree() {
// 對當前實(shí)例對象this加鎖
synchronized (this) {
}
}
public void methodFour() {
// 對class對象加鎖
synchronized (SynchronizedDemo.class) {
....
}
}
}
  volatile
  volatile適合于只有一個(gè)線(xiàn)程寫(xiě),多個(gè)線(xiàn)程讀的場(chǎng)景,因為它只能確??梢?jiàn)性。
  java編程語(yǔ)言容許線(xiàn)程訪(fǎng)問(wèn)共享變量,為了確保共享變量能被確切和一致的更新,線(xiàn)程應當確保通過(guò)排他鎖單獨獲得這個(gè)變量。Java語(yǔ)言提供了volatile,在個(gè)別情況下比鎖愈加便捷。如果一個(gè)數組被申明成volatile,java線(xiàn)程顯存模型確保所有線(xiàn)程聽(tīng)到這個(gè)變量的值是一致的。
  這句話(huà)的涵義有兩層.
  volatile 的寫(xiě)操作, 需要將線(xiàn)程本地顯存值,立馬刷新到 主顯存的共享變量中.
  volatile 的讀操作, 需要從主顯存的共享變量中讀取,更新本地內存變量的值.
  由此引出 volatile 的顯存語(yǔ)義.
  當寫(xiě)一個(gè)volatile變量時(shí),JMM會(huì )把該線(xiàn)程對應的本地顯存中的共享變量值刷新到主顯存.
  當讀一個(gè)volatile變量時(shí),JMM會(huì )把該線(xiàn)程對應的本地顯存置為無(wú)效。線(xiàn)程接下來(lái)將從主顯存中讀取共享變量,并更新本地顯存的值.
  PS :本來(lái)在JVM中有共享變量縣以及技巧的??h,棧區里有共享縣變量的高速緩存的,一般方式縣直接用高速緩存縣數據來(lái)運算。
  volatile 的特點(diǎn)
  可見(jiàn)性 : 對一個(gè)volatile的變量的讀,總是能看到任意線(xiàn)程對這個(gè)變量最后的寫(xiě)入
  互斥性 : 同一時(shí)刻只容許一個(gè)線(xiàn)程對變量進(jìn)行操作.(互斥鎖的特性)
  不具有原子性:復合操作不具有(如inc++ 等價(jià)inc= inc+ 1)
  敲黑板,劃重點(diǎn),volatitle不具有原子性的重點(diǎn)
  假如某個(gè)時(shí)刻變量inc的值為10,線(xiàn)程1對變量進(jìn)行自增操作,線(xiàn)程1先讀取了變量inc的原始值,然后線(xiàn)程1被阻塞了;
  然后線(xiàn)程2對變量進(jìn)行自增操作,線(xiàn)程2也去讀取變量inc的原始值,由于線(xiàn)程1只是對變量inc進(jìn)行讀取操作,而沒(méi)有對變量進(jìn)行更改操作,所以不會(huì )造成線(xiàn)程2的工作顯存中緩存變量inc的緩存行無(wú)效,也不會(huì )造成尋址中的值刷新,所以線(xiàn)程2會(huì )直接去尋址讀取inc的值,發(fā)現inc的值時(shí)10,然后進(jìn)行加1操作,并把11寫(xiě)入工作顯存,最后寫(xiě)入尋址。
  然后線(xiàn)程1接著(zhù)進(jìn)行加1操作,由于早已讀取了inc的值(inc++,包括3個(gè)操作python 多線(xiàn)程網(wǎng)絡(luò )爬蟲(chóng),1.讀取inc的值,2.進(jìn)行加1操作,3.寫(xiě)入新的值),注意此時(shí)在線(xiàn)程1的工作顯存中inc的值依舊為10,所以線(xiàn)程1對inc進(jìn)行加1操作后inc的值為11,然后將11寫(xiě)入工作顯存,最后寫(xiě)入尋址。
  那么兩個(gè)線(xiàn)程分別進(jìn)行了一次自增操作后,inc只降低了1。根源就在這里,自增操作不是原子性操作,而且volatile也難以保證對變量的任何操作都是原子性的。
  解決方案:可以通過(guò)synchronized或lock,進(jìn)行加鎖,來(lái)保證操作的原子性。也可以通過(guò)使用AtomicInteger
  什么是JMM
  JMM(java memory model)決定一個(gè)線(xiàn)程對共享變量的寫(xiě)入何時(shí)對另一個(gè)線(xiàn)程可見(jiàn),JMM定義了線(xiàn)程和主內存之間的具象關(guān)系:共享變量?jì)Υ嬖谥黠@存(Main Memory)中,每個(gè)線(xiàn)程都有一個(gè)私有的本地顯存(Local Memory),本地顯存保存了被該線(xiàn)程使用到的主顯存的副本拷貝,線(xiàn)程對變量的所有操作都必須在工作顯存中進(jìn)行,而不能直接讀寫(xiě)主顯存中的變量。
  
  聲明變量為volatile后 方法縣中的數據本地緩存就失效了,每次都要在主顯存中拿。
  ThreadLocal
  線(xiàn)程局部變量。進(jìn)來(lái)類(lèi)型簡(jiǎn)單點(diǎn)哦,可以理解為是個(gè)map,比如類(lèi)型 Map<Thread,Integer>python 多線(xiàn)程網(wǎng)絡(luò )爬蟲(chóng),跟Python中的線(xiàn)程局部變量類(lèi)似。
public class UseThreadLocal {
//可以理解為 一個(gè)map,類(lèi)型 Map<Thread,Integer>
static ThreadLocal<Integer> threadLaocl = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 1;
}
};
/**
* 運行3個(gè)線(xiàn)程
*/
public void StartThreadArray() {
Thread runs = new Thread[3];
for (int i = 0; i < runs.length; i++) {
runs = new Thread(new TestThread(i));
}
for (int i = 0; i < runs.length; i++) {
runs[i].start();
}
}
/**
* 類(lèi)說(shuō)明:測試線(xiàn)程,線(xiàn)程的工作是將ThreadLocal變量的值變化,并寫(xiě)回,看看線(xiàn)程之間是否會(huì )互相影響
*/
public static class TestThread implements Runnable {
int id;
public TestThread(int id) {
this.id = id;
}
public void run() {
System.out.println(Thread.currentThread().getName() + ":start");
Integer s = threadLaocl.get();//獲得變量的值
s = s + id;
threadLaocl.set(s);
System.out.println(Thread.currentThread().getName() + ":" + threadLaocl.get());
//threadLaocl.remove();
}
}
public static void main(String args) {
UseThreadLocal test = new UseThreadLocal();
test.StartThreadArray();
}
}
  wait notify
  wait是指在一個(gè)早已步入了同步鎖的線(xiàn)程內,讓自己暫時(shí)讓出同步鎖,以便其他正在等待此鎖的線(xiàn)程可以得到同步鎖并運行,只有其他線(xiàn)程調用了notify方式(notify并不釋放鎖,只是告訴調用過(guò)wait方式的線(xiàn)程可以去參與獲得鎖的競爭了,但不是馬上得到鎖,因為鎖還在他人手里,別人還沒(méi)釋放),調用wait方式的一個(gè)或多個(gè)線(xiàn)程都會(huì )解除wait狀態(tài),重新參與競爭對象鎖,程序假如可以再度得到鎖,就可以繼續向上運行。
  wait()、notify()和notifyAll()方法是本地方式,并且為final方式,無(wú)法被重畫(huà)。
  當前線(xiàn)程必須擁有此對象的monitor(即鎖),才能調用某個(gè)對象的wait()方法能使當前線(xiàn)程阻塞。(這種阻塞是通過(guò)提早釋放synchronized鎖,重新去懇求鎖造成的阻塞,這種懇求必須有其他線(xiàn)程通過(guò)notify()或者notifyAll()喚醒重新競爭獲得鎖)
  調用某個(gè)對象的notify()方法才能喚起一個(gè)正在等待這個(gè)對象的monitor的線(xiàn)程,如果有多個(gè)線(xiàn)程都在等待這個(gè)對象的monitor,則只能喚起其中一個(gè)線(xiàn)程; (notify()或者notifyAll()方法并不是真正釋放鎖,必須等到synchronized方式或則語(yǔ)法塊執行完才真正釋放鎖)
  調用notifyAll()方法才能喚起所有正在等待這個(gè)對象的monitor的線(xiàn)程,喚醒的線(xiàn)程獲得鎖的機率是隨機的,取決于cpu調度
  調用yield() 、sleep()、wait()、notify()等方式對鎖有何影響?
  線(xiàn)程在執行yield()以后,持有的鎖是不釋放的,操作系統一直可能選擇到該進(jìn)程。不釋放鎖
  sleep()方法被調用之后,持有的鎖是不釋放的,休眠期間操作系統不會(huì )再執行該進(jìn)程。不釋放鎖
  調動(dòng)方式之前,必須要持有鎖。調用了wait()方法之后,鎖都會(huì )被釋放,當wait方式返回的時(shí)侯,線(xiàn)程會(huì )重新持有鎖 .
  wait方式是面對對象的,表示當前的對象會(huì )步入阻塞,在notify/all調用以后,會(huì )重新步入就緒狀態(tài)。
  調動(dòng)方式之前,必須要持有鎖,調用notify()方法本身不會(huì )釋放鎖的,只是告訴調用過(guò)wait方式的線(xiàn)程可以去參與獲得鎖的競爭了.[/i] 查看全部
  
  一言以蔽之:Java 并發(fā)編程的目的就是充分利用計算機的資源,把計算機的性能發(fā)揮到最大
  
  什么是高并發(fā)
  并發(fā) concurrency 和并行 parallelism 的區別
  并發(fā)是指多個(gè)線(xiàn)程操作同一個(gè)資源,不是同時(shí)操作,而是交替操作,單核 CPU,只不過(guò)由于速率很快,看起來(lái)是同時(shí)執行(張三、李四,共用一口鍋煮飯,交替執行),通過(guò)時(shí)間片輪轉機制RR調度實(shí)現并發(fā)。
  速度很快,看起來(lái)象是并行。
  并行才是真正的同時(shí)執行,多核 CPU,每個(gè)線(xiàn)程使用一個(gè)獨立的 CPU 的資源來(lái)運行。(張三、李四,一人一口鍋,一起燉肉)
  并發(fā)編程是指使系統容許多個(gè)任務(wù)在重疊的時(shí)間段內執行的設計結構。
  高并發(fā)我們設計的程序,可以支持海量任務(wù)的同時(shí)執行(任務(wù)的執行在時(shí)間段上有重疊的情況)
  QPS:每秒響應的懇求數,QPS 并不是并發(fā)數。
  吞吐量:?jiǎn)挝粫r(shí)間內處理的懇求數,QPS 和并發(fā)數決定。
  平均響應時(shí)間:系統對一個(gè)懇求做出響應的平均時(shí)間,QPS = 并發(fā)數/平均響應時(shí)間
  并發(fā)用戶(hù)數:系統可以承載的最大用戶(hù)數目。
  高并發(fā)編程優(yōu)劣
  利:充分利用cpu的資源、加快用戶(hù)響應的時(shí)間,程序模塊化,異步化
  弊:線(xiàn)程共享資源,存在沖突。容易造成死鎖。 啟用太多的線(xiàn)程,就有扳倒機器的可能。
  互聯(lián)網(wǎng)項目構架中,如何提升系統的并發(fā)能力?
  垂直擴充
  水平擴充
  垂直擴充
  提升單機的處理能力
  1、增強單機的硬件性能:增加 CPU 的核數,硬盤(pán)擴容,內存升級。
  2、提升系統的構架性能:使用 Cache 來(lái)提升效率,異步懇求降低單個(gè)服務(wù)的吞吐量,使用 NoSQL 來(lái)提高數據的訪(fǎng)問(wèn)性能。
  水平擴充
  集群、分布式都是水平擴充的方案
  集群:多個(gè)人做同一件事情(3 個(gè)面點(diǎn)師同時(shí)燉肉)
  分布式:把一件復雜的事情,拆分成幾個(gè)簡(jiǎn)單的步驟,分別找不同的人去完成 (1 洗菜、2 切菜、3 炒菜)
  
  
  分布式是指多個(gè)系統協(xié)同合作完成一個(gè)特定任務(wù)的系統。分布式解決問(wèn)題,把所有解決中心化管理的任務(wù)疊加到一個(gè)節點(diǎn)處理,太慢了。把一個(gè)業(yè)務(wù)分拆為多個(gè)子業(yè)務(wù)(當某個(gè)子業(yè)務(wù)訪(fǎng)問(wèn)量突增時(shí),增加該子任務(wù)的節點(diǎn)數即可),部署在多個(gè)服務(wù)器上 ,分布式的主要工作是分解任務(wù),將職能拆解。
  集群主要的使用場(chǎng)景是為了分擔懇求的壓力,同一個(gè)業(yè)務(wù),部署在多個(gè)服務(wù)器上 ,也就是在幾個(gè)服務(wù)器上布署來(lái)==相同的應用程序,==分擔客戶(hù)端懇求。當壓力進(jìn)一步減小的時(shí)侯,可能在須要儲存的部份,mysql 無(wú)法面對好多的寫(xiě)壓力。因為在 mysql 做成集群以后,主要的寫(xiě)壓力還是在 master 的機器里面,其他 slave 機器難以分擔寫(xiě)壓力,從而這個(gè)時(shí)侯,也就引下來(lái)分布式。分布式的主要應用場(chǎng)景是單臺機器早已未能滿(mǎn)足這些性能的要求,必須要融合多個(gè)節點(diǎn),并且節點(diǎn)之間是相關(guān)之間有交互的。相當于在寫(xiě) mysql 的時(shí)侯,每個(gè)節點(diǎn)儲存部份數據,也就是分布式存儲的來(lái)歷。存儲一些非結構化數據:靜態(tài)文件、圖片、pdf、小視頻 … 這些也就是分布式文件系統的來(lái)歷。
  集群主要是。分布式中的某個(gè)子任簡(jiǎn)單加機器解決問(wèn)題,對于問(wèn)題本身不做任何分解;分布式處理里必然包含任務(wù)分解與答案歸并務(wù)節點(diǎn),可能由一個(gè)集群來(lái)取代;集群中任一節點(diǎn),都是做一個(gè)完整的任務(wù)。集群和分布式都是由多個(gè)節點(diǎn)組成,。但是集群之間的通訊協(xié)調基本不需要;而分布式各個(gè)節點(diǎn)的通訊協(xié)調必不可少RPC
  將一套系統分拆成不同子系統布署在不同服務(wù)器上(這叫分布式),
  然后布署多個(gè)相同的子系統在不同的服務(wù)器上(這叫集群),部署在不同服務(wù)器上的同一個(gè)子系統應做負載均衡。
  負載均衡集群:一個(gè)集群節點(diǎn)來(lái)接受任務(wù),然后按照其余節點(diǎn)的工作狀態(tài)(CPU,內存等信息)派發(fā)任務(wù)量, 最終實(shí)現完成任務(wù)。
  SOA:業(yè)務(wù)系統分解為多個(gè)組件,讓每位組件都獨立提供離散,自治,可復用的服務(wù)能力,通過(guò)服務(wù)的組合和編排來(lái)實(shí)現下層的業(yè)務(wù)流程
  作用:簡(jiǎn)化維護,降低整體風(fēng)險,伸縮靈活
  微服務(wù):架構設計概念,各服務(wù)間隔離(分布式也是隔離),自治(分布式依賴(lài)整體組合)其它特點(diǎn)(單一職責,邊界,異步通信,獨立布署)是分布式概念的跟嚴格執行SOA到微服務(wù)構架的演化過(guò)程 作用:各服務(wù)可獨立應用,組合服務(wù)也可系統應用。SpringClond就是太精典的微服務(wù)框架。
  具體的推行方案
  1.站點(diǎn)層擴充:Nginx 方向代理,高并發(fā)系統,一個(gè) Tomcat 帶不上去,就找十個(gè) Tomcat 去帶
  
  2.服務(wù)層擴充:通過(guò) RPC 框架實(shí)現遠程調用,Dubbo、Spring Boot/Spring Cloud,將業(yè)務(wù)邏輯分拆到不同的 RPC Client,各自完成不同的業(yè)務(wù),如果個(gè)別業(yè)務(wù)的并發(fā)量很大,就降低新的 RPC Client,理論上實(shí)現無(wú)限高并發(fā)。
  3.數據層擴充:一臺數據庫拆成多臺,主從復制、讀寫(xiě)分離、分表分庫。
  ** 進(jìn)程和線(xiàn)程**
  進(jìn)程就是計算機正在運行的一個(gè)獨立的應用程序,進(jìn)程是一個(gè)動(dòng)態(tài)的概念,必須是運行狀態(tài),如果一個(gè)應用程序沒(méi)有啟動(dòng),那就不是進(jìn)程。
  線(xiàn)程就是組成進(jìn)程的基本單位,可以完成特定的功能,一個(gè)進(jìn)程是由一個(gè)或多個(gè)線(xiàn)程組成。
  進(jìn)程和線(xiàn)程的區別在于運行時(shí)是否擁有獨立的顯存空間,每個(gè)進(jìn)程所擁有的空間都是獨立的,互不干擾,多個(gè)線(xiàn)程是共享內存空間的,但是每位線(xiàn)程的執行是互相獨立。
  線(xiàn)程必須依賴(lài)于進(jìn)程能夠執行,單獨線(xiàn)程是難以執行的,由進(jìn)程來(lái)控制多個(gè)線(xiàn)程的執行。
  Java 默認有幾個(gè)線(xiàn)程?
public class OnlyMain {
public static void main(String args) {
//虛擬機線(xiàn)程管理的接口
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
ThreadInfo threadInfos =
threadMXBean.dumpAllThreads(false, false);
for(ThreadInfo threadInfo:threadInfos) {
System.out.println("["+threadInfo.getThreadId()+"]"+" "
+threadInfo.getThreadName());
}
}
}
  Java 默認有兩個(gè)線(xiàn)程:Main 和 GC
  多線(xiàn)程實(shí)現方法
  繼承 Thread
  實(shí)現 Runnable
  實(shí)現 Callable
  重點(diǎn):Thread 是線(xiàn)程對象,Runnable 是任務(wù),一線(xiàn)程啟動(dòng)的時(shí)侯一定是對象。
  
```java
package com.southwind.demo;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test {
public static void main(String args) {
MyCallable myCallable = new MyCallable();
FutureTask futureTask = new FutureTask(myCallable);
Thread thread = new Thread(futureTask);
thread.start();
//獲取Callable的返回值
try {
System.out.println(futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class MyCallable implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println("callable");
return "hello";
}
}
  Runnable對象是Thread構造函數的參數,而Callable對象是FutureTask構造函數的參數,利用FutureTask這個(gè)對象,構建出最后的線(xiàn)程Thread。
  Runable和Thread承繼以后的時(shí)侯,都須要重畫(huà)run技巧。而Callable對象,重寫(xiě)的是call方式。
  Callable 與 Runnable 的區別:
  Callable 的 call 方法有返回值,Runnable 的 run 方法沒(méi)有返回值。
  Callable 的 call 方法可以?huà)伋霎惓?,Runnable 的 run 方法不能拋出異常。
  在外部通過(guò) FutureTask 的 get 方法異步獲取執行結果,FutureTask 是一個(gè)可以控制的異步任務(wù),是對 Runnable 實(shí)現的一種承繼和擴充。
  get 方法可能會(huì )形成阻塞,一般置于代碼的最后。Callable 有緩存。
  線(xiàn)程狀態(tài)
  
  線(xiàn)程只有6種狀態(tài)。整個(gè)生命周期就是這幾種狀態(tài)的切換。
  run()和start() :run方式就是普通對象的普通方式,只有調用了start()后,Java就會(huì )將線(xiàn)程對象和操作系統中實(shí)際的線(xiàn)程進(jìn)行映射,再來(lái)執行run技巧。
  yield() :Thread.yield(),讓出cpu的執行權,將線(xiàn)程從運行轉入可運行狀態(tài),但是下個(gè)時(shí)間片,該線(xiàn)程仍然有可能被再度選中運行 。
  線(xiàn)程的優(yōu)先級 取值為1~10,缺省為5,最高10最低1,但線(xiàn)程的優(yōu)先級不可靠,只是一個(gè)大幾率執行而已,不建議作為線(xiàn)程開(kāi)發(fā)時(shí)侯
  守護線(xiàn)程:和主線(xiàn)程共死,finally不能保證一定執行
  synchronized 用法
  修飾實(shí)例方式,對當前實(shí)例對象this加鎖
public class SynchronizedDemo {

public synchronized void methodOne() {
.....
}
}
  修飾靜態(tài)方式,對當前類(lèi)的Class對象加鎖
public class SynchronizedDemo {
public static synchronized void methodTwo() {
......
}
}
  修飾代碼塊,指定加鎖對象,對給定對象加鎖
public class SynchronizedDemo {
public void methodThree() {
// 對當前實(shí)例對象this加鎖
synchronized (this) {
}
}
public void methodFour() {
// 對class對象加鎖
synchronized (SynchronizedDemo.class) {
....
}
}
}
  volatile
  volatile適合于只有一個(gè)線(xiàn)程寫(xiě),多個(gè)線(xiàn)程讀的場(chǎng)景,因為它只能確??梢?jiàn)性。
  java編程語(yǔ)言容許線(xiàn)程訪(fǎng)問(wèn)共享變量,為了確保共享變量能被確切和一致的更新,線(xiàn)程應當確保通過(guò)排他鎖單獨獲得這個(gè)變量。Java語(yǔ)言提供了volatile,在個(gè)別情況下比鎖愈加便捷。如果一個(gè)數組被申明成volatile,java線(xiàn)程顯存模型確保所有線(xiàn)程聽(tīng)到這個(gè)變量的值是一致的。
  這句話(huà)的涵義有兩層.
  volatile 的寫(xiě)操作, 需要將線(xiàn)程本地顯存值,立馬刷新到 主顯存的共享變量中.
  volatile 的讀操作, 需要從主顯存的共享變量中讀取,更新本地內存變量的值.
  由此引出 volatile 的顯存語(yǔ)義.
  當寫(xiě)一個(gè)volatile變量時(shí),JMM會(huì )把該線(xiàn)程對應的本地顯存中的共享變量值刷新到主顯存.
  當讀一個(gè)volatile變量時(shí),JMM會(huì )把該線(xiàn)程對應的本地顯存置為無(wú)效。線(xiàn)程接下來(lái)將從主顯存中讀取共享變量,并更新本地顯存的值.
  PS :本來(lái)在JVM中有共享變量縣以及技巧的??h,棧區里有共享縣變量的高速緩存的,一般方式縣直接用高速緩存縣數據來(lái)運算。
  volatile 的特點(diǎn)
  可見(jiàn)性 : 對一個(gè)volatile的變量的讀,總是能看到任意線(xiàn)程對這個(gè)變量最后的寫(xiě)入
  互斥性 : 同一時(shí)刻只容許一個(gè)線(xiàn)程對變量進(jìn)行操作.(互斥鎖的特性)
  不具有原子性:復合操作不具有(如inc++ 等價(jià)inc= inc+ 1)
  敲黑板,劃重點(diǎn),volatitle不具有原子性的重點(diǎn)
  假如某個(gè)時(shí)刻變量inc的值為10,線(xiàn)程1對變量進(jìn)行自增操作,線(xiàn)程1先讀取了變量inc的原始值,然后線(xiàn)程1被阻塞了;
  然后線(xiàn)程2對變量進(jìn)行自增操作,線(xiàn)程2也去讀取變量inc的原始值,由于線(xiàn)程1只是對變量inc進(jìn)行讀取操作,而沒(méi)有對變量進(jìn)行更改操作,所以不會(huì )造成線(xiàn)程2的工作顯存中緩存變量inc的緩存行無(wú)效,也不會(huì )造成尋址中的值刷新,所以線(xiàn)程2會(huì )直接去尋址讀取inc的值,發(fā)現inc的值時(shí)10,然后進(jìn)行加1操作,并把11寫(xiě)入工作顯存,最后寫(xiě)入尋址。
  然后線(xiàn)程1接著(zhù)進(jìn)行加1操作,由于早已讀取了inc的值(inc++,包括3個(gè)操作python 多線(xiàn)程網(wǎng)絡(luò )爬蟲(chóng),1.讀取inc的值,2.進(jìn)行加1操作,3.寫(xiě)入新的值),注意此時(shí)在線(xiàn)程1的工作顯存中inc的值依舊為10,所以線(xiàn)程1對inc進(jìn)行加1操作后inc的值為11,然后將11寫(xiě)入工作顯存,最后寫(xiě)入尋址。
  那么兩個(gè)線(xiàn)程分別進(jìn)行了一次自增操作后,inc只降低了1。根源就在這里,自增操作不是原子性操作,而且volatile也難以保證對變量的任何操作都是原子性的。
  解決方案:可以通過(guò)synchronized或lock,進(jìn)行加鎖,來(lái)保證操作的原子性。也可以通過(guò)使用AtomicInteger
  什么是JMM
  JMM(java memory model)決定一個(gè)線(xiàn)程對共享變量的寫(xiě)入何時(shí)對另一個(gè)線(xiàn)程可見(jiàn),JMM定義了線(xiàn)程和主內存之間的具象關(guān)系:共享變量?jì)Υ嬖谥黠@存(Main Memory)中,每個(gè)線(xiàn)程都有一個(gè)私有的本地顯存(Local Memory),本地顯存保存了被該線(xiàn)程使用到的主顯存的副本拷貝,線(xiàn)程對變量的所有操作都必須在工作顯存中進(jìn)行,而不能直接讀寫(xiě)主顯存中的變量。
  
  聲明變量為volatile后 方法縣中的數據本地緩存就失效了,每次都要在主顯存中拿。
  ThreadLocal
  線(xiàn)程局部變量。進(jìn)來(lái)類(lèi)型簡(jiǎn)單點(diǎn)哦,可以理解為是個(gè)map,比如類(lèi)型 Map<Thread,Integer>python 多線(xiàn)程網(wǎng)絡(luò )爬蟲(chóng),跟Python中的線(xiàn)程局部變量類(lèi)似。
public class UseThreadLocal {
//可以理解為 一個(gè)map,類(lèi)型 Map<Thread,Integer>
static ThreadLocal<Integer> threadLaocl = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 1;
}
};
/**
* 運行3個(gè)線(xiàn)程
*/
public void StartThreadArray() {
Thread runs = new Thread[3];
for (int i = 0; i < runs.length; i++) {
runs = new Thread(new TestThread(i));
}
for (int i = 0; i < runs.length; i++) {
runs[i].start();
}
}
/**
* 類(lèi)說(shuō)明:測試線(xiàn)程,線(xiàn)程的工作是將ThreadLocal變量的值變化,并寫(xiě)回,看看線(xiàn)程之間是否會(huì )互相影響
*/
public static class TestThread implements Runnable {
int id;
public TestThread(int id) {
this.id = id;
}
public void run() {
System.out.println(Thread.currentThread().getName() + ":start");
Integer s = threadLaocl.get();//獲得變量的值
s = s + id;
threadLaocl.set(s);
System.out.println(Thread.currentThread().getName() + ":" + threadLaocl.get());
//threadLaocl.remove();
}
}
public static void main(String args) {
UseThreadLocal test = new UseThreadLocal();
test.StartThreadArray();
}
}
  wait notify
  wait是指在一個(gè)早已步入了同步鎖的線(xiàn)程內,讓自己暫時(shí)讓出同步鎖,以便其他正在等待此鎖的線(xiàn)程可以得到同步鎖并運行,只有其他線(xiàn)程調用了notify方式(notify并不釋放鎖,只是告訴調用過(guò)wait方式的線(xiàn)程可以去參與獲得鎖的競爭了,但不是馬上得到鎖,因為鎖還在他人手里,別人還沒(méi)釋放),調用wait方式的一個(gè)或多個(gè)線(xiàn)程都會(huì )解除wait狀態(tài),重新參與競爭對象鎖,程序假如可以再度得到鎖,就可以繼續向上運行。
  wait()、notify()和notifyAll()方法是本地方式,并且為final方式,無(wú)法被重畫(huà)。
  當前線(xiàn)程必須擁有此對象的monitor(即鎖),才能調用某個(gè)對象的wait()方法能使當前線(xiàn)程阻塞。(這種阻塞是通過(guò)提早釋放synchronized鎖,重新去懇求鎖造成的阻塞,這種懇求必須有其他線(xiàn)程通過(guò)notify()或者notifyAll()喚醒重新競爭獲得鎖)
  調用某個(gè)對象的notify()方法才能喚起一個(gè)正在等待這個(gè)對象的monitor的線(xiàn)程,如果有多個(gè)線(xiàn)程都在等待這個(gè)對象的monitor,則只能喚起其中一個(gè)線(xiàn)程; (notify()或者notifyAll()方法并不是真正釋放鎖,必須等到synchronized方式或則語(yǔ)法塊執行完才真正釋放鎖)
  調用notifyAll()方法才能喚起所有正在等待這個(gè)對象的monitor的線(xiàn)程,喚醒的線(xiàn)程獲得鎖的機率是隨機的,取決于cpu調度
  調用yield() 、sleep()、wait()、notify()等方式對鎖有何影響?
  線(xiàn)程在執行yield()以后,持有的鎖是不釋放的,操作系統一直可能選擇到該進(jìn)程。不釋放鎖
  sleep()方法被調用之后,持有的鎖是不釋放的,休眠期間操作系統不會(huì )再執行該進(jìn)程。不釋放鎖
  調動(dòng)方式之前,必須要持有鎖。調用了wait()方法之后,鎖都會(huì )被釋放,當wait方式返回的時(shí)侯,線(xiàn)程會(huì )重新持有鎖 .
  wait方式是面對對象的,表示當前的對象會(huì )步入阻塞,在notify/all調用以后,會(huì )重新步入就緒狀態(tài)。
  調動(dòng)方式之前,必須要持有鎖,調用notify()方法本身不會(huì )釋放鎖的,只是告訴調用過(guò)wait方式的線(xiàn)程可以去參與獲得鎖的競爭了.
[/i]

官方客服QQ群

微信人工客服

QQ人工客服


線(xiàn)

亚洲国产精品无码久久大片,亚洲AV无码乱码麻豆精品国产,亚洲品质自拍网站,少妇伦子伦精品无码STYLES,国产精久久久久久久