1. java多線程環境中,如何保證多個線程按指定的順序執行呢?
1.1 通過thread的join方法保證多線程的順序執行, wait是讓主線程等待
比如一個main方法里面先后運行thread1,,thread2,thread3,那么thread1.start()之后,運行thread1.join(),這是會讓主線程mian等待新的線程thread1執行完了,再執行主線程mian下面的代碼,thread1.join()是然主線程main wait。
package com.java.yj;
/**
* Created by yejian on 2018/7/9.
*/
public class MultiThread {
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new Thread1());
thread1.start();
thread1.join();
Thread thread2 = new Thread(new Thread2());
thread2.start();
thread2.join();
Thread thread3 = new Thread(new Thread3());
thread3.start();
}
public static class Thread1 implements Runnable{
@Override
public void run() {
System.out.println("Thread1");
}
}
public static class Thread2 implements Runnable{
@Override
public void run() {
System.out.println("Thread2");
}
}
public static class Thread3 implements Runnable{
@Override
public void run() {
System.out.println("Thread3");
}
}
}
1.2 ExecutorService executor = Executors.newSingleThreadExecutor()
java5以后提供的一個多線程操作方法,創建一個只有一個線程的線程池操作,會創建一個線程隊列,按FIFO的順序執行里面的線程。
package com.java.yj;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by yejian on 2018/7/9.
*/
public class MultiThread2 {
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(new Thread1());
executor.submit(new Thread2());
executor.submit(new Thread3());
executor.shutdown();
}
public static class Thread1 implements Runnable{
@Override
public void run() {
System.out.println("Thread1");
}
}
public static class Thread2 implements Runnable{
@Override
public void run() {
System.out.println("Thread2");
}
}
public static class Thread3 implements Runnable{
@Override
public void run() {
System.out.println("Thread3");
}
}
}
2. java中的volatile和synthronized
2.1JMM-java memory model
解決並發過程中如何處理可見性,原子性,有序性的問題
runnable ,thread。
並發編程中的2個關鍵問題:
a. 線程間如何通信 --wait() notify() notifyAll()
a) 共享內存 -隱式通信
b) 消息傳遞 - 顯示通信
b. 線程之間如何同步
在共享內存的並發模型中,同步是顯示做的; synchronized
在消息傳遞的並發模型中,由於小時發送必須在消息接受之前,所以同步是隱式的
2.2. 定位內存可見性問題
什么對象是內存共享的 ,什么不是,堆內存的對象,java虛擬機棧
JMM定義了線程和主內存之間的一個關系。線程之間通訊,必須通過主內存通訊。
volatile、synchronized
volatile 功能,聲明了volatile的變量,進行寫操作的時候,jvm會向處理器發送一條Lock的前綴指令,會把這個變量所在緩存行的數據寫回到系統內存。
在多處理器的情況下,保證各個處理器緩存一致性的特點,會實現緩存一致性協議。改變了值的volatile變量,在其他行程被指為失效狀態其他線程要使用這個變量,需要重新到駐村里面去取。
synchronized:可重入鎖、互斥性、可見性
volatile 可以做到原子性,可見性,不能做到復合操作的原子性
比如: volatile int i;
i++ 讀取i的值,給i加1,把新的值賦值給i,這個i++操作在多線程環境下是無法保證原子性的
synchronized后面鎖定的對象,可以是一個類對象,也可以是一個成員變量。
第一個線程進來調用monitorener 和monitorexit實現,獲取對象的監視器,釋放對象監視器
后續進程過來,如果monitor還沒有釋放,那么他獲取不到這個對象的monitor,會放到一個對列里面:synthronizedQueue。 等到對象的鎖釋放了,通知synthronizedQueue出隊列,獲取那個monitor。
3. Lock和synchronized
Lock是java5以后出現的,在juc包: java.util.concurrentlocks
3.1 synthronized的鎖什么時候釋放
1.1 獲取鎖的線程執行完了該代碼塊
1.2 線程出現異常
3.2 synchronized的缺陷
2.1 讀寫沖突
3.3 Lock可以主動去釋放鎖,而synchronized是被動的
ReadWriteLock
ReadLock
WriteLock
ReenterantLock可重入鎖
可中斷鎖
公平鎖 等待一個鎖的實際越長,獲取這個鎖的幾率越高
ReenterantReadWriteLock 可重入讀寫鎖
Lock是java里面的一個接口,有豐富的實現,而synchronized是java的一個關鍵字,是一個內置的功能
競爭資源激烈的情況,Lock性能優於synchronized,但是jdk7,8對synchronized做了很多優化,性能差異不大。