進程歷史
疑問:進程和線程的區別
答:進程是資源分配的最小單位,手握操作系統給他分配的monney,是分包商
線程是CPU調度的最小單位,不持有資源,去請求進程的資源,並消耗資源
進程是搶佔處理機的調度單位,擁有內存中虛擬空間
線程屬於某個進程,佔用該進程的地址空間
疑問:什麼是資源?
答:資源信息包括程序段、數據集,所有與進程相關的資源,都被記錄在PCB中。
疑問:線程擁有什麼?
答:堆棧寄存器、程序計數器和TCB
Java採用單線程編程模型,程序主動創建主線程。
疑問:什麼是單線程編程模型
答:不特殊指定,默認是主線程。有耗時操作,放在子線程裏。
主線程往往最後執行完畢,最後死掉。
疑問:既然是單線程模型,那JVM是否是單線程模型?
答:JVM實例創建之時,有多線程,如GC、
創建線程
方式1
public class CreateThread {
public static void main(String[] args) {
Thread t1 = new Thread();
Thread t2 = new Thread() {
@Override
public void run() {
System.out.println("==========");
}
};
t1.start();
t2.start();
System.out.println(t1.getName());
System.out.println(t2.getName());
Thread t3 = new Thread("MyName");
Thread t4 = new Thread(() -> {
System.out.println("Runnable...");
});
System.out.println(t3.getName());
System.out.println(t4.getName());
Thread t5 = new Thread(() -> {
System.out.println("Runnable..." + Thread.currentThread().getName());
}, "RunnableThread");
t5.start();
}
}
方式2
public class CreateThread2 {
public static void main(String[] args) {
Thread t = new Thread() {
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t.start();
// System.out.println(t.getThreadGroup());
// System.out.println(Thread.currentThread().getName());
ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
// System.out.println(threadGroup.getName());
System.out.println(threadGroup.activeCount());
Thread[] threads = new Thread[threadGroup.activeCount()];
threadGroup.enumerate(threads);
Arrays.asList(threads).forEach(System.out::println);
}
}
方式3 主線程
public class CreateThread3 {
private int i = 0;
private byte[] bytes = new byte[1024];
private static int counter = 0;
//JVM will create a thread named "main"
public static void main(String[] args) {
//create a JVM stack
try {
add(0);
} catch (Error e) {
e.printStackTrace();
System.out.println(counter);
}
}
private static void add(int i) {
++counter;
add(i + 1);
}
}
方式4
public class CreateThread4 {
private static int counter = 1;
public static void main(String[] args) {
Thread t1 = new Thread(null, new Runnable() {
@Override
public void run() {
try {
add(1);
} catch (Error e) {
System.out.println(counter);
}
}
private void add(int i) {
counter++;
add(i + 1);
}
}, "Test", 1 << 24);
t1.start();
}
}
方式5
public class CreateThread5 {
private static int counter = 1;
public static void main(String[] args) {
try {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
counter++;
new Thread(new Runnable() {
@Override
public void run() {
try {
add(1);
} catch (Error e) {
// System.out.println(counter);
}
}
private void add(int i) {
add(i + 1);
}
}).start();
}
} catch (Error e) {
counter++;
}
System.out.println("Total created thread nums=>" + counter);
}
}
Thread的start與run區別
start會創建新的子線程,並啓動
run只是Trhead的普通方法調用,仍然在主線程執行。
Thread與Runnable區別
線程設置Daemon、優先級、ID
Daemon線程
public class DaemonThread {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " running");
Thread.sleep(100000);
System.out.println(Thread.currentThread().getName() + " done.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}; //new
t.start();
t.setDaemon(true);
//runnable ->running| ->dead| ->blocked
Thread.sleep(5_000); //JDK1.7
System.out.println(Thread.currentThread().getName());
}
}
/**
* A<---------------------------------->B
* ->daemonThread(health check)
* */
Daemon線程2
public class DaemonThread2 {
public static void main(String[] args) {
Thread t = new Thread(() -> {
Thread innerThread = new Thread(() -> {
try {
while (true) {
System.out.println("Do some thing for health check.");
Thread.sleep(1_000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
//innerThread.setDaemon(true);
innerThread.start();
try {
Thread.sleep(1_000);
System.out.println("T thread finish done.");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
//t.setDaemon(true);
t.start();
}
}
線程ID、優先級
普通場景
public class ThreadSimpleAPI {
public static void main(String[] args) {
Thread t = new Thread(() -> {
Optional.of("Hello").ifPresent(System.out::println);
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "t1");
t.start();
Optional.of(t.getName()).ifPresent(System.out::println);
Optional.of(t.getId()).ifPresent(System.out::println);
Optional.of(t.getPriority()).ifPresent(System.out::println);
}
}
實際場景
public class ThreadSimpleAPI2 {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
Optional.of(Thread.currentThread().getName() + "-Index" + i).ifPresent(System.out::println);
}
});
t1.setPriority(Thread.MAX_PRIORITY);
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
Optional.of(Thread.currentThread().getName() + "-Index" + i).ifPresent(System.out::println);
}
});
t2.setPriority(Thread.NORM_PRIORITY);
Thread t3 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
Optional.of(Thread.currentThread().getName() + "-Index" + i).ifPresent(System.out::println);
}
});
t3.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
t3.start();
}
}
工具jconsole
線程中斷1
public class ThreadClose {
private static class Worker extends Thread {
@Override
public void run() {
while (true) {
if (Thread.interrupted())
break;
}
//-------------
//-------------
//-------------
}
}
public static void main(String[] args) {
Worker worker = new Worker();
worker.start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
worker.interrupt();
}
}
線程中斷2
public class ThreadService {
private Thread executeThread;
private boolean finished = false;
public void execute(Runnable task) {
executeThread = new Thread() {
@Override
public void run() {
Thread runner = new Thread(task);
runner.setDaemon(true);
runner.start();
try {
runner.join();
finished = true;
} catch (InterruptedException e) {
//e.printStackTrace();
}
}
};
executeThread.start();
}
public void shutdown(long mills) {
long currentTime = System.currentTimeMillis();
while (!finished) {
if ((System.currentTimeMillis() - currentTime) >= mills) {
System.out.println("任務超時,需要結束他!");
executeThread.interrupt();
break;
}
try {
executeThread.sleep(1);
} catch (InterruptedException e) {
System.out.println("執行線程被打斷!");
break;
}
}
finished = false;
}
}
JMM內存模型、線程安全
什麼是Java內存模型中的happens-before
Java內存模型JMM
Java內存模型(即JavaMemoryModel,簡MM)本身是一種抽象的念,
並不真實存在它描述的是一組規則或規範,通過這組規範定義了程序中各個
變量(包括實例字段,靜態字段和構成數組對象的元素)的訪問方式·
JMM中的主內存
-存儲」ava實例對象
-聲包括成員變量、類信息、常量、靜態變量等
-聲屬於數據共享的區域,多線程併發操作時會引發線程安全問題
JMM與Java內存區域劃分是不同的概念層冫欠
-jMM描述的是一組規則,圍繞原子性,有序性、可見性展開
-相似點:存在共享區域和私有區域
jMM中的主內存和工作內存
主內存與工亻乍內存的存儲類型以及操亻乍方式歸納
-方法裏的基本數據舉型本地變量將直接存儲在工作內存的棧幀結構
-引用類型的本地變量:引用存儲在工作內存中,實例存儲在主內存
-成員變量、static變量、類信息均會被存儲在主內存中
-主內存共享的方式是線程各拷貝刪分數據到工作內存,操作完成
後刷新回主內存
volatile和synchronized的區別
demo實力:
volatile和synchronized的區別
1.vo丨ati|e本質是在告訴」VM當前變量在寄存器(工作內存)中的值是不確
定的,需要從主存中讀取,synchronized則是鎖定當前變量,只有當前
線程可以訪問該變量,其他線程被阻塞住直到該線程完成變量操亻乍爲止
2,vo|ati|e僅能使用在變量級別;synchronized則可以使用在變量、方法
和類級別
3.v引ati|e僅能實現變量的修改可見性,不能保證原子性而
syn(hronized則可以保證變量修改的可見性和原子性
4,vo丨ati|e不會造成線程的阻塞,syn(hronized可能會造成線程的阻塞
5.volati|e標記的變量不會被編譯器優化,synchronizedfii己的變量可以
被編譯器優化
synchronized和lock區別
1)Lock是一個接口,而synchronized是Java中的關鍵字,synchronized是內置的語言實現;
2)synchronized在發生異常時,會自動釋放線程佔有的鎖,因此不會導致死鎖現象發生;而Lock在發生異常時,如果沒有主動通過unLock()去釋放鎖,則很可能造成死鎖現象,因此使用Lock時需要在finally塊中釋放鎖;
3)Lock可以讓等待鎖的線程響應中斷,而synchronized卻不行,使用synchronized時,等待的線程會一直等待下去,不能夠響應中斷;
4)通過Lock可以知道有沒有成功獲取鎖,而synchronized卻無法辦到。
5)Lock可以提高多個線程進行讀操作的效率。
在性能上來說,如果競爭資源不激烈,兩者的性能是差不多的,而當競爭資源非常激烈時(即有大量線程同時競爭),此時Lock的性能要遠遠優於synchronized。所以說,在具體使用時要根據適當情況選擇。
synchronized與線程安全
恰當的合理的上鎖,是線程安全的關鍵
synchronized安全問題的主要誘因
聲存在共享數據他稱臨界資源)
龍存在多條線程共同操作這些共享數據
解決問題的根本方法
同一時刻有且只有一個線程在操作共享數據其他線程必須等到該線
程處理完數據後再對共享數據進行操作
synchronized互斥鎖(原子性)的特性
互斥性·即在同一時間只允許一個線程持有某個對象鎖,通過這種特性
來實現多線程的協調機制,這樣在同一時間只有一個線不寸需要同步的
代碼塊(複合操作)進行訪問。互斥性也稱爲操作的原子性。
可見性:必須確保在鎖被釋放之前,對共享變量所做的修改,對於隨後
獲得該鎖的另一個線程是可見的(即在獲得鎖時應獲得最新共享變量的
值),否貝刂另一個線程可能是在本地緩存的某個副本上繼續操作,從而引起不一致。
synchronized鎖的不是代碼,鎖的都是對象
synchronized
根據獲取的鎖的分類·獲取對象鎖和獲取類鎖
獲取對象鎖的兩種用法
1.同步代碼塊(synchronized(this),synchronized(類實例對
象)),鎖是小括號0中的實例對象。
2,同步非靜態方法(synchronizedmethod)鎖是當前對象的實
例對象。
疑問:waite與sleep的區別
疑問:線程的生命週期