Java高並發-多線程基礎
阿新 • • 發佈:2018-04-05
nts mark read extends 機會 應用 source 進程 void
一、什麽是線程
線程是進程內的執行單元。
二、線程的基本操作
2.1 狀態與操作
2.2 新建線程
Thread t1 = new Thread(new CreateThread());
t1.start();
# 直接覆蓋run方法
# 傳target實例,即Runnable接口實例
2.3 終止線程
2.4 中斷線程
public void Thread.interrupt(); // 中斷線程
public boolean Thread.isInterrupted(); // 判斷是否被中斷
public static boolean Thread.interrupted(); // 判斷是否被中斷,並清除當前中斷狀態
public static native void sleep(long millis) throws InterruptedException
代碼
// 線程t1
public void run() {
while(true) {
Thread.yield();
}
}
// 對線程t1進行中斷操作,線程t1並不會做出響應
t1.interrupt();
// 執行下面這段代碼的線程,會對中斷做出響應
public void run() {
while(true) {
if (Thread.currentThread().isInterrupted ()) {
System.out.println("Interrupted!");
break;
}
Thread.yield();
}
}
sleep代碼
// 在等待的過程中,也對中斷操作做出響應
public void run() {
while(true) {
if (Thread.currentThread().isInterrupted()) {
System.out.println('Interrupted!');
break ;
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println("Interrupted When Sleep");
// 設置中斷狀態,拋出異常後會清除中斷標記位
Thread.currentThread().interrupt();
}
Thread.yield();
}
}
2.5 掛起和繼續執行線程
suspend()不會釋放鎖
如果加鎖發生在resume()之前,則發生死鎖
這兩個就法不推薦使用
模擬死鎖:
public class BadSuspend {
public static Object u = new Object();
static ChangeObjectThread t1 = new ChangeObjectThread("t1");
static ChangeObjectThread t2 = new ChangeObjectThread("t2");
public static class ChangeObjectThread extends Thread {
public ChangeObjectThread(String name) {
super.setName(name);
}
@Override
public void run() {
synchronized(u) {
System.out.println("in " + getName());
Thread.currentThread().suspend();
}
}
}
public static void main(String[] args) throws InterruptedException {
t1.start();
Thread.sleep(100);
t2.start();
t1.resume();
t2.resume();
t1.join();
t2.join();
}
}
分析:
t1線程正常結束,t2線程死鎖
2.6 等待線程結束和謙讓
join,yeild
// 把自己占用的CPU機會釋放掉,再和別人一起競爭CPU
public static native void yield();
// 當前線程未做完,主線程等待當前線程做完後再往下走
public final void join() throws InterruptedException
public final synchronized void join(long millis) throws InterruptedException
三、守護線程
在後臺默默地完成一些系統性的服務,比如垃圾回收線程、JIT線程就可以理解為守護線程
當一個Java應用內,只有守護線程時,Java虛擬機就會自然退出
四、線程優先級
高優先級的線程更容易在競爭中獲勝
t1.setPriority(Thread.MAX_PRIORITY);
五、基本的線程同步操作
5.1 synchronized
指定加鎖對象:對給定對象加鎖,進入同步代碼前要獲得給定對象的鎖。
直接作用於實例方法:相當於對當前實例加鎖,進入同步代碼前要獲得當前實例的鎖。
直接作用於靜態方法:相當於對當前類加鎖,進入同步代碼前要獲得當前類的鎖。
指定加鎖對象
public class AccountingSync implements Runnable {
static AccountingSync instance = new AccountingSync();
static int i = 0;
@Override
public void run() {
for (int j=0;j<100000;j++) {
synchronized(instance) {
i++;
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
作用於實例方法:註意多個線程要對同一個實例加鎖
public class AccountingSync2 implements Runnable {
static AccountingSync2 instance = new AccountingSync2();
static int i = 0;
public synchronized void increase() {
i++;
}
@Override
public void run() {
for (int j=0;j<100000;j++) {
increase();
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
作用於靜態方法:註意區別 作用於實例方法
5.2 wait()/notify()
notify()之後,允許線程往下走,但是如果沒有獲得鎖的話,也還是執行不了,t2.notifyAll()之後t1就可以往下執行了,但是此時t1還未獲得object鎖,必須等t2睡2秒後,獲得object鎖後執行。
Java高並發-多線程基礎