進程與線程
什么是進程?進程是操作系統(tǒng)結構的基礎,是程序在一個數(shù)據(jù)集合上運行的過程单寂,是系統(tǒng)進行資源分配和調度的基本單位贬芥。進程可以被看作程序的實體,同樣宣决,它也是線程的容器蘸劈。
什么是線程?線程是操作系統(tǒng)調度的最小單元疲扎,也叫作輕量級進程昵时。在一個進程中可以創(chuàng)建多個線程,這些線程都擁有各自的計數(shù)器椒丧、堆棧和局部變量等屬性壹甥,并且能夠訪問共享的內存變量。
線程的狀態(tài)
-
New:新創(chuàng)建的狀態(tài)壶熏。線程被創(chuàng)建句柠,還沒有調用
start
方法,在線程運行之前還有一些基礎工作要做棒假。 -
Runnable:可運行狀態(tài)溯职。一旦調用
start
方法,線程就處于Runnable
狀態(tài)帽哑。一個可運行的線程可能正在運行也肯能沒有運行谜酒,這取決于操作系統(tǒng)給線程提供運行的時間。 - Blocked:阻塞狀態(tài)妻枕。表示線程被鎖阻塞僻族,它暫時不活動。
- Waiting:等待狀態(tài)屡谐。線程暫時不活動述么,并且不運行任何代碼,這消耗最少資源愕掏,直到線程調度器重新激活它度秘。
- Timed waiting:超時等待狀態(tài)。和等待狀態(tài)不同的是饵撑,它是可以在指定的時間自行返回的剑梳。
-
Terminated:終止狀態(tài)。表示當前線程已經(jīng)執(zhí)行完畢肄梨。導致線程終止有兩種情況:第一種就是
run
方法執(zhí)行完畢正常退出阻荒;第二種就是因為一個沒有捕獲的異常而終止了run
方法,導致線程進入終止狀態(tài)众羡。
線程的簡單應用
上面已經(jīng)說過侨赡,線程有多種狀態(tài),那么為什么需要這幾種狀態(tài)?或者說哪些情況會進入到這些狀態(tài)羊壹?下面我們舉例說明蓖宦。
- New新創(chuàng)建狀態(tài)
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
//do something...
}
});
System.out.println(thread.getState());
我們看打印的結果:Thread-0:NEW
,可以證明該線程處于New
狀態(tài)。
- Runnable可運行狀態(tài)
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
}
});
thread.start();
System.out.println(thread.getState());
首先看下打印的結果:Thread-0:RUNNABLE
油猫。線程創(chuàng)建完成后我們調用start
方法稠茂,線程會進入Runnable
狀態(tài)。
- Blocked阻塞狀態(tài)
這里解釋下什么叫阻塞狀態(tài)情妖?運行的線程在獲取對象的同步鎖時睬关,若該同步鎖被別的線程占用,該線程將進入阻塞狀態(tài)毡证,如下示例电爹。
public class Thread9 {
static Object object = new Object();
public static void main(String[] args) {
ThreadA threadA = new ThreadA();
ThreadB threadB = new ThreadB();
threadA.setName("threadA");
threadB.setName("threadB");
threadA.start();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
threadB.start();
System.out.println(threadA.getName() + ":" + threadA.getState());
System.out.println(threadB.getName() + ":" + threadB.getState());
}
static class ThreadA extends Thread{
@Override
public void run() {
synchronized (object) {
while(true) {
}
}
};
}
static class ThreadB extends Thread{
@Override
public void run() {
synchronized (object) {
System.out.println("ThreadB");
}
};
}
}
打印結果:
threadA:RUNNABLE
threadB:BLOCKED
上面的例子中,開啟兩個線程A和B料睛,A丐箩、B線程的run
方法中獲取同一對象的同步鎖,由于A線程一直持有Object對象,B線程的任務無法進行恤煞,會進入阻塞狀態(tài)屎勘。當A線程任務完成或出現(xiàn)異常將不再持有該對象時,B線程將進入到Runnable
狀態(tài)居扒。
- Waiting等待狀態(tài)
線程暫時不活動概漱,并且不運行任何代碼,調用
wait()
或join()
(實際上也是調用wait()
方法)方法可進入該狀態(tài)喜喂,調用notify()
或notifyAll()
方法解除狀態(tài)犀概,示例如下。
調用
join()
方法
package thread;
public class JoinTest {
public static void main(String[] args) throws InterruptedException{
Thread1 thread1 = new Thread1();
thread1.setName("Thread-1");
thread1.start();
System.out.println("begin");
Thread.sleep(2000);
System.out.println(thread1.getName() + ":" + thread1.getState());
}
static class Thread1 extends Thread {
@Override
public void run(){
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread-2:running");
}
}
});
thread2.setName("Thread-2");
thread2.start();
try {
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end");
}
}
}
打印結果:
begin
Thread-2:running
Thread-1:WAITING
Thread-2:running
Thread-2:running
Thread-2:running
Thread-2:running
end
在線程1中再開啟一個線程2夜惭,線程2開始后調用join()
方法,然后查看線程1的狀態(tài)铛绰。
調用
wait()
方法
package thread;
import java.util.concurrent.TimeUnit;
public class WaitTest{
public synchronized void waittest() throws InterruptedException {
System.out.println("start");
wait();
System.out.println("over");
}
public synchronized void notifyTest() {
notifyAll();
}
public static void main(String[] args) throws InterruptedException{
WaitTest waitTest = new WaitTest();
Thread mainThread = Thread.currentThread();
MyThread myThread = new MyThread(mainThread,waitTest);
mainThread.setName("Thread-main");
myThread.setName("Thread-0");
myThread.start();
waitTest.waittest();
}
static class MyThread extends Thread{
Thread thread;
WaitTest waitTest;
public MyThread(Thread thread,WaitTest waitTest) {
this.thread = thread;
this.waitTest = waitTest;
}
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println(thread.getName()
+ ":" + thread.getState());
int i = 0;
do {
i++;
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.currentThread().getName()
+ ":" + this.currentThread().getState());
} while (i < 5);
waitTest.notifyTest();
}
}
}
打印結果:
start
Thread-main:WAITING
Thread-0:RUNNABLE
Thread-0:RUNNABLE
Thread-0:RUNNABLE
Thread-0:RUNNABLE
Thread-0:RUNNABLE
over
開啟一個新線程,然后主線程調用wait()
方法(必須使用同步字synchronized加鎖诈茧,否則會報異常),查看主線程的狀態(tài)捂掰。
通過上面兩個示例我們可以看到敢会,調用wait()
和join()
方法都可以使線程進入WAITING狀態(tài),但是它們兩者是有區(qū)別的(它們的區(qū)別以后會講到这嚣,這里就不詳細比較了)鸥昏。
- Timed waiting超時等待狀態(tài)
Timed waiting和Waiting的不同之處在于,Timed waiting有時間限制姐帚,時間到了之后將自行解除該狀態(tài)吏垮。
package thread;
public class TimeWaitIngTest {
public static void main(String[] args) {
ThreadA threadA = new ThreadA();
ThreadA threadB = new ThreadA();
ThreadA threadC = new ThreadA();
threadA.setName("thread-A");
threadB.setName("thread-B");
threadC.setName("thread-C");
threadA.start();
threadB.start();
threadC.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadA.getName()
+ ":" + threadA.getState());
System.out.println(threadB.getName()
+ ":" + threadB.getState());
System.out.println(threadC.getName()
+ ":" + threadC.getState());
}
static class ThreadA extends Thread{
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class ThreadB extends Thread{
@Override
public void run() {
try {
wait(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class ThreadC extends Thread{
@Override
public void run() {
try {
join(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
打印結果:
thread-A:TIMED_WAITING
thread-B:TIMED_WAITING
thread-C:TIMED_WAITING
開啟三個線程,分別調用sleep(long)
、wait(long)
和join(long)
方法膳汪,看這三個線程的狀態(tài)唯蝶。
- TERMINATED終止狀態(tài)
package thread;
public class TerminatedTest {
public static void main(String[] args) throws InterruptedException{
MyThread myThread = new MyThread();
myThread.setName("MyThread");
System.out.println(myThread.getName()
+ ":" + myThread.getState());
myThread.start();
Thread.sleep(10);
System.out.println(myThread.getName()
+ ":" + myThread.getState());
}
static class MyThread extends Thread{
@Override
public void run() {
}
}
}
打印結果:
MyThread:NEW
MyThread:TERMINATED
新建一個線程,然后執(zhí)行遗嗽,看線程的狀態(tài)變化粘我。
綜上所訴,線程一般有6種狀態(tài)痹换,下面用一張圖來總結
線程狀態(tài)