進程與線程
進程:系統資源調度與分配的基本單位,一個進程至少有一個線程,進程裏面的線程共享進程資源(網絡、磁盤空間、內存)
線程:cpu分配的基本單位(CPU資源共享)
線程共享區和線程獨享區
線程的生命週期
新建狀態(new):當線程對象創建後,即新建狀態;
就緒狀態(Runnable):當線程調用start()方法時,線程進入就緒狀態,等待CPU時間片的分配;
運行狀態(Running):當就緒狀態的線程獲取到CPU分配的時間片時,此刻線程進入運行狀態;
阻塞狀態(Blocked):處於運行狀態中的線程由於某種原因,暫時放棄對CPU的使用權,停止執行,此時進入阻塞狀態,
直到其進入到就緒狀態,纔有機會再次被CPU調用以進入到運行狀態;
阻塞的分類
① 同步阻塞:當前線程執行時候需要去獲取鎖的時候(鎖可能被其他線程佔用未被釋放),此刻當前線程會
進入阻塞狀態 (synchronized);
② 等待阻塞:當前線程調用wait()方法時,會進入等待阻塞狀態,直到當前線程被通知纔會繼續執行,一般和
notify()和notifyAll()方法聯合使用;
③ 其他阻塞:當前線程調用join()會sleep()會進入阻塞狀態,當sleep()狀態超時、join()等待線程終止或者超時、
或者I/O處理完畢時,線程重新轉入就緒狀態;
死亡狀態(Dead):當前線程執行完成或者異常退出,那麼當前線程生命週期結束。
線程創建的幾種方式
方式1:通過繼承Thread創建線程,重寫run()方法實現業務
public class ThreadDemo extends Thread {
@Override
public void run() {
System.out.println("嗨!我是通過繼承Thread類創建的線程"+this.getName()+",麼麼噠!!!");
}
public static void main(String[] args) {
//方式1運行
ThreadDemo threadDemo = new ThreadDemo();
Thread thread = new Thread(threadDemo);
thread.start();
//方式2運行
new ThreadDemo().start();
}
}
嗨!我是通過繼承Thread類創建的線程Thread-2,麼麼噠!!!
嗨!我是通過繼承Thread類創建的線程Thread-0,麼麼噠!!!
方式2:實現Runnable接口創建線程類,重寫run()實現業務
public class ThreadDemo1 implements Runnable {
private static volatile int money = 1;
/**
* @see Thread#run()
*/
@Override
public void run() {
System.out.println("嗨,我是通過實現Runnable接口創建的線程"+Thread.currentThread().getName()+"!!!麼麼噠");
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new ThreadDemo1());
thread.start();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("thread1 修改成員屬性---> " + ++money);
}
});
thread1.start();
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("thread2 修改成員屬性---> " + ++money);
}
});
thread2.start();
}
}
嗨,我是通過實現Runnable接口創建的線程Thread-0!!!麼麼噠
thread1 修改成員屬性---> 2
thread2 修改成員屬性---> 3
方式3:通過實現Callable接口創建線程,重寫call()方法實現業務
@Data
@ToString
public class User {
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
}
public class ThreadDemo2 implements Callable<User> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
@Override
public User call() throws Exception {
System.out.println("嗨!我是實現Callable<T> 接口創建的線程"+Thread.currentThread().getName()+",我有返回值哦,麼麼噠!!!");
return new User("麼麼噠", 1);
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
ThreadDemo2 threadDemo2 = new ThreadDemo2();
FutureTask<User> futureTask = new FutureTask<User>(threadDemo2);
new Thread(futureTask).start();
User user = futureTask.get();
System.out.println(user);
}
}
嗨!我是實現Callable<T> 接口創建的線程Thread-0,我有返回值哦,麼麼噠!!!
User(name=麼麼噠, age=1)
方式4:使用線程池例如用Executor框架,後續再詳解
幾種方式創建線程優缺點比較
通過繼承Thread:
優點:編寫簡單,如果需要訪問當前線程,則無須使用Thread.currentThread()方法,直接使用this即可獲得當前線程;
缺點:繼承了Thread不能再繼承其他類,擴展性不好,不適應於多線程;
通過實現Runnable接口:
優點:可以繼承其他類、擴展性好;通過上面thread1、thread2操作money可以看出,實現接口可以多線程target的共享,適用於多線程;
缺點:編程稍稍複雜,不能使用Thread的方法,如果需要訪問當前線程,則必須使用Thread.currentThread()方法;
通過實現Callable接口:
優點:可以繼承其他類、擴展性好;多個線程可以共享同一個target對象,所以非常適合多個相同線程來處理同一份資源的情況,非常適合創建多線程;和Runnable不同的是,該方式有返回值,可以做一些業務處理;
缺點:編程稍稍複雜,不能使用Thread的方法,如果需要訪問當前線程,則必須使用Thread.currentThread()方法;
總結:Thread編程簡單,不適用多線程環境;Runnable、Callable編程稍微複雜點,但是非常適合多線程環境;
Callable有返回值;
線程常用方法介紹