java基礎(chǔ) 線程
參考詳細(xì):Java之多線程
一礼搁、創(chuàng)建線程
創(chuàng)建線程常見有兩種方式望浩,另外有兩種新增方式
1.Thread
/**
新建線程方式一:繼承Thread蓖宦,重寫run()
*/
public static void test1(){
Thread1 thread1 = new Thread1();
thread1.setName("thread1");
thread1.start();
}
static class Thread1 extends Thread{
int i;
@Override
public void run() {
while (i < 100){
++i;
System.out.println(this.getName() + " 優(yōu)先級(jí) "+this.getPriority()+":" + i);
}
}
}
2.Runnable
/**
* 新建線程方式二:實(shí)現(xiàn)Runnable有序,實(shí)現(xiàn)run();將Runnable作為Thread創(chuàng)建的實(shí)參
*/
public static void test2(){
Runnable runnable = new Runnable() {
int i;
@Override
public void run() {
while (i < 100){
++i;
System.out.println(Thread.currentThread().getName() + " 優(yōu)先級(jí) "+Thread.currentThread().getPriority()+":" + i);
}
}
};
Thread thread2 = new Thread(runnable,"thread2");
thread2.start();
}
3.Callable --- JDK5.0新增
/**
* 新增·方式三:實(shí)現(xiàn)Callable接口,此功能支持有泛型返回值蜻拨,支持拋出異常,需借助FutureTask類
*/
public static void test3() throws ExecutionException, InterruptedException {
Callable callable = getCallable();
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread thread3 = new Thread(futureTask);
thread3.start();
// 返回值
Integer integer = futureTask.get();
System.out.println("方式三:main獲得結(jié)果-"+integer);
}
private static Callable getCallable(){
Callable<Integer> callable = new Callable<Integer>() {
int i;
@Override
public Integer call() throws Exception {
while (i < 100){
++i;
System.out.println(Thread.currentThread().getName() + " 優(yōu)先級(jí) "+Thread.currentThread().getPriority()+":" + i);
}
return i;
}
};
return callable;
}
4.ThreadPool --- JDK5.0新增
/**
* 新增·方式四:使用線程池創(chuàng)建線程
*/
public static void test4() throws ExecutionException, InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(5);
ThreadPoolExecutor service1 = (ThreadPoolExecutor)service;
Callable callable = getCallable();
Future future = service1.submit(callable);
System.out.println("方式四:main獲得結(jié)果-"+future.get());
service.shutdown();
}
private static Callable getCallable(){
Callable<Integer> callable = new Callable<Integer>() {
int i;
@Override
public Integer call() throws Exception {
while (i < 100){
++i;
System.out.println(Thread.currentThread().getName() + " 優(yōu)先級(jí) "+Thread.currentThread().getPriority()+":" + i);
}
return i;
}
};
return callable;
}
步驟:
1)提供指定線程池
ExecutorService service = Executors.newXXXThreadPool()
設(shè)置線程池屬性
ThreadPoolExecutor service1 = ()service;
service1.setXXX
2)執(zhí)行指定線程的操作桩引,需要提供實(shí)現(xiàn)Runnable接口或Callable接口庫實(shí)現(xiàn)類的對象
service.execute(xxx); // xxx為實(shí)現(xiàn)Runnable接口的類的對象
service.submit(xxx); // xxx為實(shí)現(xiàn)Callable接口的類的對象缎讼,返回結(jié)果Future類
3)關(guān)閉連接池
service.shutdown();
二、線程屬性方法
1.Thread類的有關(guān)方法
1)start():啟動(dòng)當(dāng)前線程坑匠,調(diào)用當(dāng)前線程的run()
2)run():通常需要重寫Thread類中的此方法血崭,將創(chuàng)建的線程需要處理的邏輯寫在這里
3)currentThread():靜態(tài)方法,返回執(zhí)行當(dāng)前代碼的線程 this = Thread.currentThread()
4)getName():獲得當(dāng)前線程的名字
5)setName():設(shè)置當(dāng)前線程的名字
6)yield():釋放當(dāng)前cpu的執(zhí)行權(quán)
7)join():在線程a中調(diào)用線程b的join()厘灼,此時(shí)線程a就進(jìn)入阻塞狀態(tài)夹纫,直到線程b完全執(zhí)行完成以后,線程a就是阻塞狀態(tài)
8)stop():已過時(shí)设凹。當(dāng)執(zhí)行此方法舰讹,強(qiáng)制結(jié)束當(dāng)前線程
9)sleep(long millitime):讓當(dāng)前線程“睡眠”指定millitime毫秒。在指定的毫秒內(nèi)闪朱,當(dāng)前線程阻塞狀態(tài)月匣。
10)isAlive():判斷當(dāng)前線程是否存活
2.線程優(yōu)先級(jí)
1)等級(jí):
MAX_PRIORITY:10,MIN_PRIORITY:1奋姿,NORM_PRIORITY:5
2)如何獲取和設(shè)置當(dāng)前線程優(yōu)先級(jí)
getPriority():獲取當(dāng)前線程優(yōu)先級(jí)
setProority(int p):設(shè)置當(dāng)前線程優(yōu)先級(jí)
高優(yōu)先級(jí)線程要搶占低優(yōu)先級(jí)線程cpu執(zhí)行權(quán)锄开。但是只是從概率上講。
3.生命周期
yield()
- yield() 讓當(dāng)前正在運(yùn)行的線程回到可運(yùn)行狀態(tài)称诗,以允許具有相同優(yōu)先級(jí)的其他線程獲得運(yùn)行的機(jī)會(huì)萍悴。因此,使用yield()的目的是讓具有相同優(yōu)先級(jí)的線程之間能夠適當(dāng)?shù)妮啌Q執(zhí)行寓免。但是退腥,實(shí)際中無法保證yield()達(dá)到讓步的目的,因?yàn)樵匍尣降木€程可能被線程調(diào)度程序再次選中
4.線程通信
方法
1)wait():使得調(diào)用wait()的線程進(jìn)入阻塞狀態(tài)狡刘,并釋放同步監(jiān)視器
2)notify():一旦執(zhí)行此方法,就會(huì)喚醒被wait的一個(gè)線程困鸥。如果多個(gè)線程被wait嗅蔬,喚醒優(yōu)先級(jí)高的
3)notifyAll():一旦執(zhí)行此方法剑按,就會(huì)喚醒被wait的所有線程
說明
1)wait(),notiry()澜术,notiryAll()需要聲明在同步代碼塊或者同步代碼方法中
2)wait()艺蝴,notiry(),notiryAll()調(diào)用者必須是同步代碼塊或者同步代碼方法的同步監(jiān)視器鸟废,否則會(huì)出現(xiàn)異常
3)wait()猜敢,notiry(),notiryAll()聲明在java.lang.Object當(dāng)中
sleep() VS wait()
- sleep() 方法是線程類(Thread)的靜態(tài)方法盒延,調(diào)用此方法讓當(dāng)前線程暫停執(zhí)行指定的時(shí)間缩擂,將執(zhí)行機(jī)會(huì)(CPU)讓給其他線程,但是對象的鎖依然保持添寺,因此休眠時(shí)間結(jié)束后會(huì)自動(dòng)恢復(fù)(線程回到就緒狀態(tài))
- wait() 是Object類的方法胯盯,調(diào)用對象的wait()方法導(dǎo)致當(dāng)前線程放棄對象的鎖(線程暫停執(zhí)行),進(jìn)入對象的等待池(wait pool)计露,只有調(diào)用對象的notify()方法(或notifyAll()方法)時(shí)才能喚醒等待池中的線程進(jìn)入等鎖池(lock pool)博脑,如果線程重新獲得對象的鎖就可以進(jìn)入就緒狀態(tài)
總結(jié)
- 不同:sleep()鎖在,wait()鎖不在票罐。sleep()時(shí)間結(jié)束自動(dòng)恢復(fù)叉趣;wait()等待notify()(或notifyAll()方法)喚醒
- 同:調(diào)用方法進(jìn)入阻塞狀態(tài)
三、線程同步機(jī)制
1.同步代碼塊
synchronized(同步監(jiān)視器){
//需要同步的代碼
}
同步監(jiān)視器:類的對象
要求:多個(gè)線程必須要共用同一把鎖该押,可以考慮使用this疗杉,類.class等
2.同步方法
將synchronized
添加到方法
synchronized method():同步監(jiān)視器是this
static synchronized method():同步監(jiān)視器是類.class
3.Lock鎖 --- JDK5.0新增
- 從JDK 5.0開始,Java提供了更強(qiáng)大的線程同步機(jī)制--通過顯式定義同步鎖對象來實(shí)現(xiàn)同步沈善。同步鎖使用Lock對象充當(dāng)乡数。
- java.util.concurrent.locks.Lock接口是控制多個(gè)線程對共享資源進(jìn)行訪問的工具。鎖提供了對共享資源的獨(dú)占訪問闻牡,每次只能有一個(gè)線程對Lock對象加鎖净赴,線程開始訪問共享資源之前應(yīng)先獲得Lock對象。
- ReentrantLock類實(shí)現(xiàn)了Lock罩润,它擁有與 synchronized相同的并發(fā)性和內(nèi)存語義玖翅,在實(shí)現(xiàn)線程安全的控制中,比較常用的是 Reentrantlock割以,可以顯式加鎖金度、釋放鎖
class A {
//1.實(shí)例化ReentrantLock對象
private final ReenTrantLock lock = new ReenTrantLook();
public void m (){
lock.lock//2.先加鎖
try{
//保證線程同步的代碼
}finally{
lock.unlock();//3.后解鎖
}
}
}
//注意:如果同步代碼塊有異常,要將unlock()寫入finally語句塊中