2.大資料學習之旅——紅黑樹
紅黑樹
自平衡二叉查詢樹 — 時間複雜度O(logn)
特徵:
- 每一個節點非紅即黑
- 根節點一定是黑色
- 所有的葉子節點一定是黑色的nil節點
- 紅節點的子節點一定是黑節點
- 任意一條路徑中的黑色節點個數一致
- 插入的節點一定是紅色
修復:
- 當前節點為紅,並且父節點且叔父節點為紅,那麼將父節點以及叔父
節點塗黑,然後將祖父節點塗紅 - 當前節點為紅,並且父節點為紅且叔父節點為黑,當前節點為右子
葉,以當前節點為軸進行左旋 - 當前節點為紅,並且父節點為紅且叔父節點為黑,當前節點為左子
葉,以父節點為軸進行右旋
ConcurrentNavigableMap - 併發導航對映
本身是一個介面,所以更多的是使用實現類 - ConcurrentSkipListMap - 併發
跳躍表對映
跳躍表:為了提高查詢效率所產生一種資料結構 — 跳躍表是典型的以空
間換時間的產物
如果跳躍表中插入新的元素,新的元素是否往上提取遵循"拋硬幣"原則 —
1/2原則 - 只要保證這個節點有一半的概率被提取就可以
跳躍表適合於大量查詢而不增刪的場景
擴充套件:B+樹是MySQl的索引的建立機制
鎖
CountDownLatch - 閉鎖 - 執行緒遞減鎖 - 對執行緒進行計數,當計數歸零的時
候會放開阻塞讓執行緒繼續往下執行
package cn.tedu.concurrent.lock;
import java.util.concurrent.CountDownLatch;
CountDownLatch cdl = new CountDownLatch(5);
new Thread(new Teacher(cdl)).start();
new Thread(new Student(cdl)).start();
public static void main(String[] args) throws InterruptedException {
public class CountDownLatchDemo {
分割槽 Concurrent 的第 3 頁
new Thread(new Student(cdl)).start();
new Thread(new Student(cdl)).start();
new Thread(new Student(cdl)).start();
new Thread(new Student(cdl)).start();
// 表示讓執行緒阻塞,直到計數歸零的時候阻塞才能放開
cdl.await();
System.out.println("考試結束~~~");
}
}
private CountDownLatch cdl;
class Student implements Runnable {
this.cdl = cdl;
public Student(CountDownLatch cdl) {
}
@Override
System.out.println("學生來到考場,準備考試~~~");
Thread.sleep(1000);
try {
e.printStackTrace();
} catch (InterruptedException e) {
}
System.out.println("學生交卷離開考場");
// 計數-1
cdl.countDown();
public void run() {
}
}
private CountDownLatch cdl;
class Teacher implements Runnable {
this.cdl = cdl;
public Teacher(CountDownLatch cdl) {
}
@Override
public void run() {
System.out.println("老師來到考場,準備考試~~~");
Thread.sleep(5000);
try {
e.printStackTrace();
} catch (InterruptedException e) {
}
System.out.println("老師收卷離開了考場~~~");
cdl.countDown();
}
}
CyclicBarrier - 柵欄 - 當所有的執行緒都到達了同一個點之後才繼續往下執行
package cn.tedu.concurrent.lock;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierDemo {
CyclicBarrier cb = new CyclicBarrier(4);
new Thread(new Runner(cb), "1號").start();
new Thread(new Runner(cb), "2號").start();
new Thread(new Runner(cb), "3號").start();
new Thread(new Runner(cb), "4號").start();
public static void main(String[] args) {
}
}
private CyclicBarrier cb;
this.cb = cb;
public Runner(CyclicBarrier cb) {
}
class Runner implements Runnable {
Thread.sleep((long) (10000 * Math.random()));
try {
e.printStackTrace();
} catch (InterruptedException e) {
}
String name = Thread.currentThread().getName();
System.out.println(name + "選手到了起跑線~~~");
// 表示讓當前執行緒陷入阻塞
// await每執行一次,就會自動減少一個計數
// 當計數減為0的時候,阻塞就會自動放開
// 也就意味著當所有的被計數的執行緒都到達這個點之後才會放開阻塞繼續向下執行
cb.await();
try {
e.printStackTrace();
} catch (InterruptedException | BrokenBarrierException e) {
}
System.out.println(name + "選手聽到槍響,跑了出去~~~~");
public void run() {
分割槽 Concurrent 的第 5 頁
System.out.println(name + "選手聽到槍響,跑了出去~~~~");
}
}
Exchanger - 交換機 - 用於交換兩個執行緒之間的資訊的
package cn.tedu.concurrent.lock;
import java.util.concurrent.Exchanger;
public class ExchangerDemo {
public static void main(String[] args) {
Exchanger<String> ex = new Exchanger<>();
new Thread(new Spy1(ex)).start();
new Thread(new Spy2(ex)).start();
}
}
class Spy1 implements Runnable {
// 泛型表示交換的資訊型別
private Exchanger<String> ex;
this.ex = ex;
public Spy1(Exchanger<String> ex) {
}
@Override
public void run() {
String info = "天王蓋地虎";
// 要和第二個執行緒交換資訊
// 獲取到了交換過來的資訊
String msg = ex.exchange(info);
System.out.println("間諜1收到了間諜2的資訊:" + msg);
try {
e.printStackTrace();
} catch (InterruptedException e) {
}
}
}
class Spy2 implements Runnable {
private Exchanger<String> ex;
this.ex = ex;
public Spy2(Exchanger<String> ex) {
}
@Override
public void run() {
String info = "寶塔鎮河妖";
分割槽 Concurrent 的第 6 頁
// 和第一個執行緒交換資訊
// 換過來第一個執行緒的資訊
String msg = ex.exchange(info);
System.out.println("間諜2收到了間諜1的資訊:" + msg);
try {
e.printStackTrace();
} catch (InterruptedException e) {
}
}
}
Semaphore - 訊號量 - 用於計數 - 訊號在被用完之後,後來的執行緒就會被
阻塞,直到有訊號被歸還,被阻塞的執行緒才能取得訊號繼續執行
package cn.tedu.concurrent.lock;
import java.util.concurrent.Semaphore;
Semaphore s = new Semaphore(10);
new Thread(new Restaurant(s)).start();
for (int i = 0; i < 15; i++) {
}
public static void main(String[] args) {
}
public class SemaphoreDemo {
}
class Restaurant implements Runnable {
private Semaphore s;
this.s = s;
public Restaurant(Semaphore s) {
}
@Override
// 獲取到了1個訊號,使計數-1
s.acquire();
try {
e.printStackTrace();
} catch (InterruptedException e) {
}
System.out.println("一位客人佔用了一張桌子~~~");
Thread.sleep((long) (10000 * Math.random()));
try {
e.printStackTrace();
} catch (InterruptedException e) {
}
System.out.println("一位客人起身離開,空出一張桌子~~~");
// 釋放1個訊號,使計數+1
s.release();
public void run() {
}
分割槽 Concurrent 的第 7 頁
}
執行緒池
執行緒池 - 如果每一個請求對應一個執行緒,那麼會導致執行緒大量的建立和銷
毀。減少執行緒的建立和銷燬,希望能夠重複使用已有的執行緒,有了執行緒
池 — 儲存執行緒的佇列
特點:
- 執行緒池在建立的時候裡面是沒有執行緒的
- 當過來請求的時候,就會執行緒池中建立一個執行緒來處理這個請求。當
請求處理完畢的時候,執行緒就會還回執行緒池,等待下一個請求 - 核心執行緒線上程池中需要限定數量 3.
如果所有的核心執行緒都在使用,那麼再來的請求就會放入工作佇列
中。工作佇列是一個阻塞式佇列。 - 如果所有的核心執行緒都被佔用並且工作佇列已滿,那麼會建立臨時線
程去處理新的請求 - 臨時執行緒處理完請求之後並不是立即銷燬,而是存活一段時間,如果
過了這段時間依然沒有新的請求,那麼臨時執行緒就被銷燬
package cn.tedu.concurrent.pool;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolDemo {
public static void main(String[] args) {
// 執行器服務
// corePoolSize - 核心執行緒數量
// maximumPoolSize - 執行緒池的容量 = 核心執行緒數量 + 臨時執行緒數量
// keepAliveTime - 臨時執行緒的存活事件
// unit - 時間單位
// workQueue - 工作佇列
// handler - 拒絕執行助手
new ArrayBlockingQueue<Runnable>(5), new RejectedExecutionHandler() {
ExecutorService es = new ThreadPoolExecutor(5, 10, 3000, TimeUnit.MILLISECONDS,
@Override
System.out.println(new Thread(r).getName() + "執行緒被拒絕~~~");
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
}
});
// 執行執行緒
es.execute(new RDemo());
for (int i = 0; i < 17; i++) {
}
// 關閉執行緒池
es.shutdown();
}
}
class RDemo implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":hello");
Thread.sleep(8000);
try {
e.printStackTrace();
} catch (InterruptedException e) {
}
}
}
java提供的執行緒池
package cn.tedu.concurrent.pool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolDemo2 {
分割槽 Concurrent 的第 9 頁
public static void main(String[] args) {
// 獲取快取執行緒池
// 特點:
// 1. 沒有核心執行緒,所有執行緒都是臨時執行緒
// 2. 執行緒池的容量可以認為是無限的
// 3. 每一個臨時執行緒存活時間都是1min - 存活時間不長
// 4. 工作佇列是一個同步佇列 - 只能儲存一個元素
// 總結:
// 1. 大池子小佇列
// 2. 理論上能夠處理任意多的請求
// 3. 適合於短任務場景,例如:聊天
// ExecutorService es = Executors.newCachedThreadPool();
// 混合執行緒池
// 特點:
// 1. 需要指定核心執行緒數量
// 2. 只有核心執行緒,沒有臨時執行緒
// 3. 工作佇列是阻塞式鏈式佇列,沒有指定容量
// 總結:
// 1. 小池子大佇列
// 2. 理論上能夠儲存任意多的請求
// 3. 適合於長任務場景,例如:檔案下載
ExecutorService es = Executors.newFixedThreadPool(5);
}
}
Callable和Runnable的區別:
- Runnable執行緒可以通過Thread啟動執行,也可以通過執行緒池啟動執行;
Callable只能通過執行緒池來執行 - Runnable沒有容錯機制,一旦出現異常需要自己處理;Callable可以將
異常丟擲利用全域性的方式來進行處理
ScheduledExecutorService - 定時執行者服務
package cn.tedu.concurrent.pool;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledExecutorServiceDemo {
public static void main(String[] args) {
// 建立了定時執行緒池
// 建立了定時執行緒池
ScheduledExecutorService ses = Executors.newScheduledThreadPool(5);
// 定時執行
// command - 執行緒
// delay - 推遲的時間數量
// unit - 時間單位
// 表示執行緒池開啟之後,延遲5s再初始化並且執行執行緒
ses.schedule(new ScheduledRunnable(), 5, TimeUnit.SECONDS);
ses.shutdown();
}
}
class ScheduledRunnable implements Runnable {
@Override
System.out.println("hello");
public void run() {
}
}
package cn.tedu.concurrent.pool;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledExecutorServiceDemo2 {
public static void main(String[] args) {
ScheduledExecutorService ses = Executors.newScheduledThreadPool(5);
// 每5秒鐘迴圈執行一個執行緒
// command - 執行緒
// initialDelay - 初始延遲時間 - 當執行緒池啟動以後,執行緒需要延遲多長時間才能執行
// period - 間隔時間
// unit - 時間單位
// 以上一次的起始時間開始計算
// 如果執行緒的執行時間超過了指定的間隔時間
// 那麼第二次執行緒不會立即啟動而是等上一個執行緒執行完成之後再啟動執行
// ses.scheduleAtFixedRate(new RDemo2(), 0, 5, TimeUnit.SECONDS);
// delay - 表示執行緒上次完成之後需要間隔多長時間再執行下一次
// 以上一次的結束實際開始計算
ses.scheduleWithFixedDelay(new RDemo2(), 0, 5, TimeUnit.SECONDS);
// 凌晨1點對資料進行更新
// 獲取當前時間 - 計算當前時間到凌晨一點的時間間隔
// 每執行一次這個方法,就在當前時間上加上1天
}
}
class RDemo2 implements Runnable {
@Override
System.out.println("hi");
try {
e.printStackTrace();
} catch (InterruptedException e) {
}
}
}
分叉合併 - For and Join
將一個大任務不斷的分成許多個小任務(分叉),小任務在執行完成之後
再將結果進行彙總(合併)
任務在分叉之後會分發到CPU不同的核上去,然後利用核進行資料的處
理。原來的for迴圈只是在一個核上來執行的程式碼,所以就導致分叉合併的
效率要高於for迴圈
分叉合併採取了work-stealing(工作竊取)策略來實現執行緒的高效操作 -當
一個核上的所有執行緒執行完成,就會隨機挑一個核,從這個核的執行緒佇列
中偷取最後一個執行緒回來,然後執行
分叉合併會帶來資源共享問題
package cn.tedu.concurrent.pool;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
public class ForkJoinPoolDemo {
public static void main(String[] args) {
long start = System.currentTimeMillis();
ForkJoinPool fk = new ForkJoinPool();
Long sum = fk.invoke(new Calc(1, 100000000000L));
fk.
相關推薦
2.大資料學習之旅——紅黑樹
紅黑樹
自平衡二叉查詢樹 — 時間複雜度O(logn)
特徵:
每一個節點非紅即黑
根節點一定是黑色
所有的葉子節點一定是黑色的nil節點
紅節點的子節點一定是黑節點
任意一條路徑中的黑色節點個數一致
插入的節點一定是紅色
修復
學習之旅-紅黑樹之刪除
前人栽樹,後人乘涼。關於這樣紅黑樹的帖子已經很多。我就不再重複造輪子了。我自己發現一個刪除說的很好的部落格,連結:http://gengning938.blog.163.com/blog/static/1282253812011420103852696/
我只是說說自己的理
大資料學習之旅2——從零開始搭hadoop完全分散式叢集
前言
本文從零開始搭hadoop完全分散式叢集,大概花費了一天的時間邊搭邊寫部落格,一步一步完成完成叢集配置,相信大家按照本文一步一步來完全可以搭建成功。需要注意的是本文限於篇幅和時間的限制,也是為了突出重點,一些很基礎的操作就不再詳細
記錄我的大資料學習之旅 ---01.使用VMware安裝CentOs7
前言
從2017年初開始接觸大資料,從一無所知,到慢慢探索,到最後能夠獨立開發大資料專案。為此,趁著專案空閒的時間,分享與記錄一下我的大資料學習之旅。
一.準備資料,下載CentOs
二.新建虛擬機器
13.大資料學習之旅——HBase第三天
LSM-TREE
概述
眾所周知傳統磁碟I/O是比較耗效能的,優化系統性能往往需要和磁碟I/O打交道,而磁碟I/O產 生的時延主要由下面3個因素決定: 1)尋道時間(將磁碟臂移動到適當的柱面上所需要的時間,尋道時移動到相鄰柱面移動所需 時間1ms,而隨機移動所需時間位5~1
12.大資料學習之旅——HBase第二天
HBASE完全分散式安裝
實現步驟
準備三臺虛擬機器,01作為主節點,02、03作為從節點。(把每臺虛擬機器防火牆都關掉,配 置免密碼登入,配置每臺的主機名和hosts檔案。)
01節點上安裝和配置:Hadoop+Hbase+JDK+Zookeeper
11.大資料學習之旅——HBase
一、HBASE概述
官方網址:http://hbase.apache.org/ HBase是一個分散式的、面向列的開源資料庫,該技術來源於Fay Chang 所撰寫的Google論文《Bigtable》一個結構 化資料的分散式儲存系統"。就像Bigtable利用了Google
10.大資料學習之旅——hive2
Hive解決資料傾斜問題
概述
什麼是資料傾斜以及資料傾斜是怎麼產生的? 簡單來說資料傾斜就是資料的key 的分化嚴重不均,造成一部分資料很多,一部分資料很少的局面。 舉個 word count 的入門例子,它的map 階段就是形成 (“aaa”,1)的形式,然後在redu
9.大資料學習之旅——hive
Hive介紹
Hadoop開發存在的問題
只能用java語言開發,如果是c語言或其他語言的程式設計師用Hadoop,存 在語言門檻。 需要對Hadoop底層原理,api比較瞭解才能做開發。
Hive概述
Hive是基於Hadoop的一個數據倉庫工具。可以將結構
8.大資料學習之旅——hadoop-Hadoop完全分散式配置
Hadoop完全分散式配置
關閉防火牆
修改主機名
配置hosts檔案。將需要搭建叢集的主機全部配置到hosts檔案中
192.168.32.138 hadoop01
192.168.32.139 hadoop02
192.168.32.14
7.大資料學習之旅——hadoop-MapReduce
序列化/反序列化機制
當自定義一個類之後,如果想要產生的物件在hadoop中進行傳輸,那麼需要 這個類實現Writable的介面進行序列化/反序列化 案例:統計每一個人產生的總流量
import java.io.DataInput;
import java.io.DataOutp
5.大資料學習之旅——hadoop-HDFS
NameNode
檢視edits檔案: hdfs oev -i edits_0000000000000000022-0000000000000000023 -o edits.xml 檢視fsimage檔案: hdfs oiv -i fsimage_000000000000000002
5.大資料學習之旅——hadoop-簡介及偽分散式安裝
Hadoop簡介
是Apache的頂級專案,是一個可靠的、可擴充套件的、支援分散式計算的開源 專案。
起源
創始人:Doug Cutting 和Mike 2004 Doug和Mike建立了Nutch - 利用通用爬蟲爬取了網際網路上的所有數 據,獲取了10億個網頁資料 - 1
4.大資料學習之旅——Avro
一、概述
Avro是一種遠端過程呼叫和資料序列化框架,是在Apache的Hadoop專案之內開發的。它使用JSON來定義資料類 型和通訊協議,使用壓縮二進位制格式來序列化資料。它主要用於Hadoop,它可以為持久化資料提供一種序列化格 式,併為Hadoop節點間及從客戶端程式到
3.大資料學習之旅——Zookeeper
Zookeeper
Zookeeper是開源的分散式的協調服務框架,是Apache Hadoop的子件,適用 於絕大部分分散式叢集的管理
分散式引發問題:
死鎖:至少有一個執行緒佔用了資源,但是不佔用CPU
活鎖:所有執行緒都沒有把持資源,但是執行緒卻是在不斷地
1.大資料學習之旅——NIO
Concurrent包
jdk1.5所提供的一個針對高併發進行程式設計的包。
阻塞式佇列 - BlockingQueue
遵循先進先出(FIFO)的原則。阻塞式佇列本身使用的時候是需要指定界限。 ArrayBlockingQueue - 阻塞式順序佇列 - 底層是基於陣列來進
14.大資料學習之旅——HBASE表設計&HBase優化
HBASE表設計
Rowkey設計
Rowkey是不可分割的位元組數,按字典排序由低到高儲存在表中。 在設計HBase表時,Rowkey設計是最重要的事情,應該基於預期的訪問模式來為Rowkey建 模。Rowkey決定了訪問HBase表時可以得到的效能,原因有兩個: 1)R
16.大資料學習之旅——Storm叢集配置&Strom叢集中各角色說明&Storm併發機制*
實現步驟:
安裝和配置jdk
安裝和配置zookeeper
上傳和解壓storm
配置storm安裝目錄conf目錄下的storm.yaml檔案
storm.yaml配置示例: 注意配置項開頭需要有空格,:後面需要跟空格,否則啟動會報錯
5.
19.大資料學習之旅——flume介紹
flume介紹
概述 Flume最早是Cloudera提供的日誌收集系統,後貢獻給Apache。所以目前是Apache下的專案,Flume支援在日誌 系統中定製各類資料傳送方,用於收集資料。 Flume是一個高可用的,高可靠的魯棒性(robust 健壯性),分散式的海量日誌採集、聚合
大資料學習之Scala中main函式的分析以及基本規則(2)
一、main函式的分析
首先來看我們在上一節最後看到的這個程式,我們先來簡單的分析一下,有助於後面的學習
object HelloScala
{
def main(args: Array[String]): Unit =
{
printl