前言
進(jìn)程是計(jì)算機(jī)中程序關(guān)于某幾何數(shù)據(jù)集合上的一次運(yùn)行活動(dòng)姑躲,是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位睡扬。是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ)
線程可以說(shuō)是輕量級(jí)的進(jìn)程,是程序執(zhí)行的最小單位黍析,使用多線程而不用多進(jìn)程去進(jìn)行并發(fā)程序的設(shè)計(jì)卖怜,是因?yàn)榫€程之間的切換與調(diào)度的成本遠(yuǎn)小于進(jìn)程。
線程的幾種狀態(tài)
New狀態(tài)表示剛剛創(chuàng)建的線程阐枣,這種線程還沒有開始執(zhí)行
RUNNABLE:當(dāng)線程創(chuàng)建好之后马靠,調(diào)用線程的start方法就會(huì)進(jìn)入就緒狀態(tài)奄抽。
BLOCKED:當(dāng)線程運(yùn)行過(guò)程如果遇到了Syschronized就會(huì)進(jìn)入阻塞狀態(tài)。
TIMED_WATING:表示等待狀態(tài)甩鳄,有時(shí)間限制的(sleep)
WAITING:表示進(jìn)入一個(gè)無(wú)時(shí)間顯示的等待狀態(tài)(wait)
TERMINATED:表示結(jié)束狀態(tài)逞度。
線程的基本操作
新建線程
實(shí)現(xiàn)Runable接口或者new Thread
終止線程
為什么不建議使用stop?
因?yàn)閟top方法比較暴力,強(qiáng)行把執(zhí)行的程序終止妙啃,可能會(huì)引發(fā)數(shù)據(jù)不一致的問(wèn)題第晰,Thread.stop()
方法在結(jié)束線程時(shí),會(huì)直接終止線程彬祖,并立即釋放這個(gè)線程的所持有的鎖茁瘦。比如數(shù)據(jù)寫到一半,強(qiáng)行終止掉了储笑,數(shù)據(jù)就會(huì)被破壞甜熔。
線程中斷
interrupt() //中斷線程。相當(dāng)于設(shè)置中斷標(biāo)志位
isInterrypted() //判斷是否被中斷
interrupted() //判斷是都被中斷突倍,并清除當(dāng)前的中斷狀態(tài)
Thread.sleep()
方法由于中斷而拋出異常腔稀,此時(shí)它會(huì)清除中斷標(biāo)記,如果不加處理羽历,那么下一次循環(huán)開始時(shí)焊虏,就無(wú)法捕獲這個(gè)異常,可以再次設(shè)置中斷標(biāo)記來(lái)方便循環(huán)判斷秕磷。
等待和通知
當(dāng)在一個(gè)對(duì)象實(shí)力上條用wait()
方法之后诵闭。當(dāng)前線程就會(huì)在這個(gè)對(duì)象上等待。在線程A中調(diào)用了obj.wait()
方法澎嚣,那么變成A就會(huì)停止繼續(xù)執(zhí)行疏尿,轉(zhuǎn)為等待狀態(tài),直到其他線程調(diào)用了obj.notify()
方法才有機(jī)會(huì)繼續(xù)執(zhí)行(并不是一定)
如果一個(gè)線程調(diào)用了obj.wait()
那么它就會(huì)進(jìn)入這個(gè)object的等待隊(duì)列易桃,這個(gè)等待隊(duì)列可能會(huì)有多個(gè)線程褥琐,因?yàn)橄到y(tǒng)運(yùn)行多個(gè)線程同時(shí)等待某一個(gè)對(duì)象,當(dāng)obj.notify()
方法被調(diào)用時(shí)晤郑,就會(huì)隨機(jī)選擇一個(gè)線程敌呈,將其喚醒,這個(gè)喚醒是完全隨機(jī)的造寝。
notifyAll()
方法的功能是喚醒所有在該對(duì)象等待隊(duì)列中等待的線程磕洪。
守護(hù)線程的finally不一定會(huì)執(zhí)行。如果除守護(hù)線程外的所有線程都結(jié)束了匹舞,那么守護(hù)線程就立即退出沒有執(zhí)行finally代碼塊的機(jī)會(huì)褐鸥。
掛起(suspend)和繼續(xù)(resume)執(zhí)行
不推薦執(zhí)行suspend(),因?yàn)樵摲椒ㄔ趯?dǎo)致線程暫停的同時(shí)赐稽,并不會(huì)釋放任何資源叫榕。影響其他想要訪問(wèn)該資源的線程浑侥,直到當(dāng)前線程使用resume
操作馒胆,是當(dāng)前線程繼續(xù)執(zhí)行卡儒,但是此處有一個(gè)隱患吧兔。如果resume在suspend之前運(yùn)行了鳍徽,那么被掛起的線程將不能繼續(xù)執(zhí)行下去。
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();//無(wú)法直到這一行先執(zhí)行傍衡,還是Thread.currentThread().suspend();先執(zhí)行
t1.join();
t2.join();
}
}
等待線程結(jié)束(join)和謙讓(yeild)
public final synchronized void join(long millis) throws InterruptedException//有最大等待時(shí)長(zhǎng)的等待
public final synchronized void join(long millis, int nanos)
throws InterruptedException//毫秒词渤,加納秒級(jí)別的等待
public final void join() throws InterruptedException//表示無(wú)限期的等待
package com.atmb.me;
public class joinAndYeild {
public volatile static int i =0;
public static class myThread implements Runnable{
@Override
public void run() {
for (int j = 0; j < 1000000; j++) {
i+=1;
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new myThread());
thread.start();
thread.join();//等待thread線程執(zhí)行結(jié)束
System.out.println(i);//結(jié)果為1000000
}
}
public static native void yield();
這個(gè)方法一旦執(zhí)行猫妙,就會(huì)使當(dāng)前線程讓出cpu,讓出cpu之后尖昏,該線程會(huì)繼續(xù)進(jìn)行cpu資源的爭(zhēng)奪仰税,之后繼續(xù)正常運(yùn)行。
線程組
package com.atmb.me;
public class ThreadGroupTest implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getThreadGroup().getName()+"==="+Thread.currentThread().getName());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ThreadGroup group1 = new ThreadGroup("group1");
Thread thread1 = new Thread(group1, new ThreadGroupTest());
Thread thread2 = new Thread(group1, new ThreadGroupTest());
thread1.start();
thread2.start();
System.out.println(group1.activeCount());//活躍線程數(shù)
group1.list();
}
}
<<<
2
group1===Thread-0
java.lang.ThreadGroup[name=group1,maxpri=10]
group1===Thread-1
Thread[Thread-0,5,group1]
Thread[Thread-1,5,group1]
守護(hù)線程(Daemon)
守護(hù)線程要守護(hù)的對(duì)象已經(jīng)不存在了抽诉,那么整個(gè)應(yīng)用程序就應(yīng)該技術(shù)陨簇,因此當(dāng)java應(yīng)用內(nèi)只有守護(hù)線程時(shí),java虛擬機(jī)就會(huì)自然退出迹淌。
package geym.ch2;
public class DaemonDemo {
public static class DaemonT extends Thread{
public void run(){
while(true){
System.out.println("I am alive");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t=new DaemonT();
t.setDaemon(true);
t.start();
// Thread.sleep(2000);
}
}
設(shè)置守護(hù)線程河绽,必須要在start之前設(shè)置,否則會(huì)得到異常信息唉窃。
線程優(yōu)先級(jí)
Java中的線程可以有自己的優(yōu)先級(jí)耙饰。優(yōu)先級(jí)高的線程在競(jìng)爭(zhēng)資源時(shí),會(huì)更有優(yōu)勢(shì)纹份,更大概率搶占到資源苟跪,java中線程優(yōu)先級(jí)可以設(shè)置為1-10.
其中有三個(gè)靜態(tài)標(biāo)量標(biāo)識(shí)三個(gè)對(duì)應(yīng)的優(yōu)先級(jí)。
/**
* The minimum priority that a thread can have.
*/
public final static int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.
*/
public final static int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.
*/
public final static int MAX_PRIORITY = 10;
public class PriorityDemo {
public static class HightPriority extends Thread{
static int count=0;
public void run(){
while(true){
synchronized(PriorityDemo.class){
count++;
if(count>10000000){
System.out.println("HightPriority is complete");
break;
}
}
}
}
}
public static class LowPriority extends Thread{
static int count=0;
public void run(){
while(true){
synchronized(PriorityDemo.class){
count++;
if(count>10000000){
System.out.println("LowPriority is complete");
break;
}
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread high=new HightPriority();
LowPriority low=new LowPriority();
high.setPriority(Thread.MIN_PRIORITY);
low.setPriority(Thread.MAX_PRIORITY);
low.start();
high.start();
}
}
線程安全與關(guān)鍵字synchronized
synchronized
- 指定加鎖對(duì)象矮嫉,對(duì)給定的對(duì)象進(jìn)行加鎖削咆,
- 用于實(shí)例方法,對(duì)當(dāng)前的實(shí)例進(jìn)行加鎖
- 用于靜態(tài)方法蠢笋,對(duì)當(dāng)前類進(jìn)行加鎖
錯(cuò)誤的加鎖
package com.atmb.me;
public class lockError implements Runnable {
public static Integer i =0;
public static lockError instance = new lockError();
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(instance);
Thread thread2 = new Thread(instance);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(i);
}
@Override
public void run() {
for (int j = 0; j < 100000; j++) {
synchronized (i){
i+=1;
}
}
}
}
<<<
142957
原因在于Integer類型屬于不可變對(duì)象,一旦創(chuàng)建就不可能被改變鳞陨,當(dāng)integer對(duì)象賦值為新值時(shí)昨寞,當(dāng)前引用指向的對(duì)象就改變了。
指令重排的前提
指令重排需要保證串行語(yǔ)義的一致性厦滤,指令重排不會(huì)使串行的語(yǔ)義邏輯發(fā)生問(wèn)題援岩。
指令重排的目的?
為了減少中斷流水線
那些指令不能重排
- 程序順序原則掏导,一個(gè)線程內(nèi)保證語(yǔ)義的串行性
- volatile規(guī)則:volatile變量的寫先與讀發(fā)生享怀,寶整理volatile變量的可見性
- 傳遞性:解鎖必然發(fā)生在隨后的加鎖前
- 線程的
start()
方法先于它的動(dòng)作 - 線程的所有操作先于線程的終結(jié)(interrupt)
- 線程的中斷(
interrupt()
)先于被中斷線程的代碼 - 對(duì)象的構(gòu)造函數(shù)的執(zhí)行,結(jié)束先于
finalize()
的方法
是否會(huì)釋放鎖
yield讓出cpu執(zhí)行權(quán)趟咆,不會(huì)釋放鎖
sleep休眠時(shí)添瓷,不會(huì)釋放鎖
調(diào)用wait方法之后梅屉,會(huì)釋放鎖,喚醒之后鳞贷,會(huì)再次競(jìng)爭(zhēng)鎖坯汤,然后執(zhí)行wait()方法后的代碼
nofify nodifyall 對(duì)鎖沒有影響,一般放同步代碼塊的最后一行
最后
感謝你看到這里搀愧,看完有什么的不懂的可以在評(píng)論區(qū)問(wèn)我惰聂,覺得文章對(duì)你有幫助的話記得給我點(diǎn)個(gè)贊,每天都會(huì)分享java相關(guān)技術(shù)文章或行業(yè)資訊咱筛,歡迎大家關(guān)注和轉(zhuǎn)發(fā)文章搓幌!