java建立多執行緒&建立程序
概述
併發和並行是即相似又有區別:
- 並行:指兩個或多個事件在同一時刻發生;
- 併發:指兩個或多個事件在同一時間段內發生。
程序是指一個記憶體中執行中的應用程式。每個程序都有自己獨立的一塊記憶體空間,一個應用程式可以同時啟動多個程序。比如在Windows系統中,一個執行的abc.exe就是一個程序。 那麼我們此時就可以處理同時玩遊戲和聽音樂的問題了,我們可以設計成兩個程式,一個專門負責玩遊戲,一個專門負責聽音樂。 但是問題來了,要是要設計一個植物大戰殭屍遊戲,我得開N個程序才能完成多個功能,這樣的設計顯然是不合理的。 更何況大多數作業系統都不需要一個程序訪問其他程序的記憶體空間,也就是說程序之間的通訊很不方便。 此時我們得引入“執行緒”這門技術,來解決這個問題。
執行緒是指程序中的一個執行任務(控制單元),一個程序可以同時併發執行多個執行緒,如:多執行緒下載軟體。 一個程序至少有一個執行緒,為了提高效率,可以在一個程序中開啟多個執行任務,即多執行緒。 多程序:作業系統中同時執行的多個程式。 多執行緒:在同一個程序中同時執行的多個任務。 我們檢視Windows環境下的工作管理員: 在作業系統中允許多個任務,每一個任務就是一個程序,每一個程序也可以同時執行多個任務,每一個任務就是執行緒。
多執行緒作為一種多工、併發的工作方式,當然有其存在優勢:
- 程序之前不能共享記憶體,而執行緒之間共享記憶體(堆記憶體)則很簡單。
- 系統建立程序時需要為該程序重新分配系統資源,建立執行緒則代價小很多,因此實現多工併發時,多執行緒效率更高.
- Java語言本身內建多執行緒功能的支援,而不是單純第作為底層系統的排程方式,從而簡化了多執行緒程式設計.
用java語言建立程序
import java.io.IOException; //如何用java語言開啟一個程序 public class ProcessDemo { public static void main(String[] args) throws IOException{ //方式一:使用Runtime的exec方法 Runtime.getRuntime().exec("notepad"); //方式二:使用ProcessBuilder類中的start方法 ProcessBuilder pb = new ProcessBuilder("notepad"); pb.start(); } }
建立和啟動執行緒
方式一:繼承Thread類
- 自定義類繼承於Thread類,那麼該自定義類就是執行緒類;
2.覆寫run方法,將執行緒執行的程式碼存放在run中;
3.建立自定義類的物件,即執行緒物件;
4.呼叫執行緒物件的start方法,啟動執行緒。
package thread_create;
//繼承方式 建立和啟動執行緒
class MusicThread extends Thread{ //MusicThread是執行緒子類
public void run() { //子類必須重寫run()方法
for(int i = 0 ;i < 50;i++)
{
System.out.println("聽音樂"+i);
}
}
}
public class ExtendsThreadDemo {
public static void main(String[] args){
for(int i = 0 ;i < 50;i++)
{
System.out.println("玩遊戲"+i);
if( i == 10){
MusicThread t = new MusicThread(); //建立執行緒子類的例項
t.start(); //底層也呼叫了run(); 啟動執行緒
}
}
}
}
方式二:實現Runnable介面
1.自定義類實現Runnable介面;
2.覆寫run方法,執行緒執行的程式碼存放在run中;
3.通過Thread類建立執行緒物件,並將實現了Runnable介面的實現類物件作為引數傳遞給Thread類的構造器。
4.Thread類物件呼叫start方法,啟動執行緒。
class MusicRunnable implements java.lang.Runnable{ //注意MusicRunnable類不是執行緒類或者執行緒子類
public void run() { //介面的實現必須覆蓋方法。
for(int i = 0 ;i < 50;i++)
{
System.out.println("聽音樂"+i);
}
}
}
public class ImplementsRunnableDemo {
public static void main(String[] args){
for(int i = 0 ;i < 50;i++)
{
System.out.println("玩遊戲"+i);
if( i == 10){
Runnable t = new MusicRunnable(); //啟動執行緒必須用執行緒類物件呼叫start();
new Thread(t).start(); //類Thread的一個構造器中Thread(Runnable target)分配新的 Thread 物件。
}
}
}
}
對比兩種方法(吃蘋果比賽)
1、繼承Thread類
/**
* 案例:存在50個蘋果,現在有請三個童鞋(小A,小B,小C)上臺表演吃蘋果.
* 因為A,B,C三個人可以同時吃蘋果,此時得使用多執行緒技術來實現這個案例.
*
* 此處程式不合理,ABC每個執行緒都執行50次,即ABC每個人都吃一次編號50的蘋果
*/
class Person extends Thread{
private int num= 50;
Person(String name){
super(name);
}
public void run() {
for(int i = 0;i < 50;i++){
if(num > 0)
System.out.println(super.getName()+"吃了第"+num--+"個蘋果");
}
}
}
//使用繼承Thread的方式建立執行緒
public class ExtendsDemo {
public static void main(String[] args){
Person p1 = new Person("A");
p1.start();
Person p2 = new Person("B");
p2.start();
Person p3 = new Person("C");
p3.start();
}
}
2、實現Runnable介面
class Apple implements Runnable{
private int num = 50;
public void run(){
for(int i = 0; i< 50 ;i++){
if(num > 0){
System.out.println(Thread.currentThread().getName()+"吃了第"+num--+"個蘋果");
}//Thread.currentThread() 返回對當前正在執行的執行緒物件的引用。
}
}
}
//使用實現Runnable介面的方式,這種方法可以解決此問題
public class ImplementsDemo {
public static void main(String[] args){
Runnable r = new Apple();
new Thread(r,"A").start();
new Thread(r,"B").start();
new Thread(r,"C").start();
}
}
對比
繼承方式:
- java中類是單繼承的,如果繼承了Thread,該類就不能再有其他的直接父類
- 從操作上分析,繼承方式更簡單,獲取執行緒的名字也簡單(操作上,簡單)
- 從多執行緒共享一個資源上分析,繼承方式不能做到
實現方式
- java中類可以實現介面,此時該類還可以繼承其他類,並且可以實現介面(設計上,更優雅)
- 從操作上分析,實現方式稍微複雜點,獲取執行緒的名字比較複雜,得使用currentThread()獲取當前執行緒的引用。
- 從多執行緒共享一個資源上分析,實現方式可以做到。