java基礎4(線程)

1.請簡單描述什麼是並行,什麼是併發?java

並行:指兩個或多個事件在同一時刻發生(同時發生)。程序員

併發:指兩個或多個事件在同一個時間段內發生。網絡

通俗易懂版:多線程

你吃飯吃到一半,電話來了,你一直到吃完了之後纔去接,這就說明你不支持併發也不    支持並行。
    你吃飯吃到一半,電話來了,你停了下來接了電話,接完後繼續吃飯,這說明你支持併發。
    你吃飯吃到一半,電話來了,你一邊打電話一邊吃飯,這說明你支持並行。併發

併發的關鍵是你有處理多個任務的能力,不必定要同時。
    並行的關鍵是你有同時處理多個任務的能力。jvm

因此它們最關鍵的點就是:是不是『同時』。ide

2.請描述什麼是進程,什麼是線程,進程與線程之間的關係,並舉例說明。測試

進程指正在運行的程序。確切的來講,當一個程序進入內存運行,即變成一個進程,進程是處於運行過程當中的程序,而且具備必定獨立功能。this

線程是進程中的一個執行單元,負責當前進程中程序的執行,一個進程中至少有一個線程。一個進程中是能夠有多個線程的,這個應用程序也能夠稱之爲多線程程序。spa

一個程序運行後至少有一個進程,一個進程中能夠包含多個線程,但一個進程中至少包含一個線程。好比使用迅雷軟件下載網絡文件時,同時下載多個文件,就使用到了多線程下載。

3.自定義異常類

每個學生(Student)都有學號,姓名和分數,分數永遠不能爲負數

若是老師給學生賦值一個負數,拋出一個自定異常

/*
 1.定義異常類NoScoreException,繼承RuntimeException
a)提供空參和有參構造方法
 */

public class NoScoreException extends RuntimeException {
//  空參構造
public NoScoreException() {
super();
 }
// 有參構造
public NoScoreException(String message) {
super(message);
 }
}
/*
  2.定義學生類(Student)
 a)屬性:name,score
 b)提供空參構造
 c)提供有參構造;
  i.使用setXxx方法給名稱和score賦值
 d)提供setter和getter方法
  i.在setScore(int score)方法中
   1.首先判斷,若是score爲負數,就拋出NoScoreException,異常信息爲:分數不能爲負數:xxx.
   2.而後在給成員score賦值.
 */

public class Student {
private String name;
private int score;
// 空參構造
public Student() {
super();
 }
// c)提供有參構造;
// i.使用setXxx方法給名稱和score賦值
public Student(String name,int score){
  setName(name);
  setScore(score);
 }
// d)提供setter和getter方法

public String getName() {
return name;
 }

public void setName(String name) {
this.name = name;
 }

public int getScore() {
return score;
 }
// i.在setScore(int score)方法中
public void setScore(int score) {
// 1.首先判斷,若是score爲負數,就拋出NoScoreException,異常信息爲:分數不能爲負數:xxx.
if(score <0){
throw new NoScoreException(":分數不能爲負數:"+score);
  }
// 2.而後在給成員score賦值.
this.score = score;
 }
}
/*
3.定義測試類Test9
 a)提供main方法,在main方法中
  i.使用滿參構造方法建立Student對象,分數傳入一個負數,運行程序
  ii.因爲一旦遇到異常,後面的代碼的將不在執行,因此須要註釋掉上面的代碼
  iii.使用空參構造建立Student對象
  iv.調用setScore(int score)方法,傳入一個正數,運行程序
  v.調用setScore(int score)方法,傳入一個負數,運行程序
 */

public class Test9 {
public static void main(String[] args) {
//  i.使用滿參構造方法建立Student對象,分數傳入一個負數,運行程序
//  Student s = new Student("景甜", -10);
//  ii.因爲一旦遇到異常,後面的代碼的將不在執行,因此須要註釋掉上面的代碼

//  iii.使用空參構造建立Student對象
Student s = new Student();
//  iv.調用setScore(int score)方法,傳入一個正數,運行程序
s.setScore(100);
//  v.調用setScore(int score)方法,傳入一個負數,運行程序
s.setScore(-5);
 }
}

4.建立多線程對象,開啓多線程。在子線程中輸出1-100之間的偶數,主線程輸出1-100之間的奇數。

//自定義線程類:
public class MyThread extends Thread {

/**
  * 重寫run方法,完成該線程執行的邏輯
*/
@Override
public void run() {
    for (int i = 1; i <= 100; i++) {
        if (i % 2 == 0) {
            System.out.println("子線程打印輸出偶數:" + i);
        }
    }
}


}
//測試類:
public class Test11 {
public static void main(String[] args) {
//建立自定義線程對象
MyThread mt = new MyThread();
//開啓線程
mt.start();
//在主方法中執行for循環
for (int i = 1; i <= 100; i++) {
    if (i % 2 == 1) {
        System.out.println("主線程打印輸出奇數:" + i);
    }
}

 }
}

5.

建立三個子線程,在每一個線程中開啓10萬次的循環,線程1循環中將循環自增變量i賦值給Integer類型變量 a,線程2循環中將字符串"程序員"賦值給String類型變量b,線程3循環中將字符串"程序員"和循環自增變量i拼接後賦值給String類型變量c

分別計算三個線程完成任務所用的毫秒值

//線程1
public class Thread1 extends Thread{
    @Override
    public void run() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            Integer a = i;
        }
        long end = System.currentTimeMillis();
        System.out.println("線程1執行時間:"+(end-start));
    }
}
//線程2
public class Thread2 extends Thread{
    @Override
    public void run() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            String b = "程序員";
        }
        long end = System.currentTimeMillis();
        System.out.println("線程2執行時間:"+(end-start));
    }
}
//線程3
public class Thread3 extends Thread{
    @Override
    public void run() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            String c = "程序員"+i;
        }
        long end = System.currentTimeMillis();
        System.out.println("========線程3執行時間:"+(end-start));
    }
}
//測試類
public class TestThread {
    public static void main(String[] args) {
        new Thread1().start();
        new Thread2().start();
        new Thread3().start();
    }
}

6.請描述Thread類中的start()方法與run()方法的區別。

答:

線程對象調用run()方法不開啓線程,僅是對象調用方法。線程對象調用start()方法開啓線程,並讓jvm調用run()方法在開啓的線程中執行。

7.請描述建立線程的兩種方式。

答:

第一種方式是將類聲明爲 Thread 的子類。

  1. 定義Thread類的子類,並重寫該類的run()方法,該run()方法的方法體就表明了線程須要完成的任務,所以把run()方法稱爲線程執行體。
  2. 建立Thread子類的實例,即建立了線程對象。
  3. 調用線程對象的start()方法來啓動該線程。

 

第二種方式是聲明一個類實現Runnable 接口。

    1. 定義Runnable接口的實現類,並重寫該接口的run()方法,該run()方法的方法體一樣是該線程的線程執行體。

    2. 建立Runnable實現類的實例,並以此實例做爲Thread的target來建立Thread對象,Thread對象纔是真正的線程對象。

    3. 調用線程對象的start()方法來啓動線程。

8.請編寫程序,分別打印主線程的名稱和子線程的名稱。

         要求使用兩種方式實現:

                  第一種方式:繼承Thread類。

                  第二種方法:實現Runnable接口。

//    第一種方式:繼承Thread類
/*
 * 1.定義一個子線程的類,繼承Thread類;
 */
public class SubThread extends Thread {
 /*
  *2.在子線程類中重寫run方法,在run方法中打印子線程的名稱;
  */
 public void run() {
  // 打印子線程的名稱
  System.out.println("subThread:" + Thread.currentThread().getName());
 }
}



/*
 * 3.定義一個測試類
 */
public class ThreadDemo {
 public static void main(String[] args) {
  // 4.在main方法中打印主線程的名稱;
  System.out.println("main:" + Thread.currentThread().getName());
  // 5.在main方法中建立子線程對象;
  SubThread st = new SubThread();
  // 6.調用子線程對象的start方法,開啓子線程。
  st.start();
 }
}
//    第二種方式:實現Runnable接口
/*
 * 1.定義一個子任務類,實現Runnable接口。
 */
public class SubRunnable implements Runnable {
 @Override
 public void run() {
  // 2.在子任務類中重寫run方法,在run方法中打印子線程的名稱。
  System.out.println("SubRunnable:"+ Thread.currentThread().getName());
 }
}


/*
 * 3.定義一個測試類。
 */
public class RunnableDemo {
 public static void main(String[] args) {
  // 4.在main方法中打印主線程的名稱。
  System.out.println("RunnableDemo:"+ Thread.currentThread().getName());
  // 5.在main方法中建立一個子任務對象。
  SubRunnable r = new SubRunnable();
  // 6.在main方法中建立一個Thread類的對象,並把子任務對象傳遞給Thread類的                         構造方法。
  Thread t = new Thread(r);
  // 7.調用Thread類對象的start方法開啓子線程。
  t.start();
 }
}

9.請描述實現Runnable接口比繼承Thread類所具備的優點:

答:

1. 適合多個相同的程序代碼的線程去共享同一個資源。

2. 能夠避免java中的單繼承的侷限性。

3. 增長程序的健壯性,實現解耦操做,代碼能夠被多個線程共享,代碼和數據獨立。

4. 線程池只能放入實現Runable或callable類線程,不能直接放入繼承Thread的類。

10.請描述在線程的生命週期中, 有幾種狀態呢 

答:

  1. NEW(新建) 線程剛被建立,可是並未啓動。
  2. Runnable(可運行)

線程能夠在java虛擬機中運行的狀態,可能正在運行本身代碼,也可能沒有,這取決於操做系統處理器。

  1. Blocked(鎖阻塞)

當一個線程試圖獲取一個對象鎖,而該對象鎖被其餘的線程持有,則該線程進入Blocked狀態;當該線程持有鎖時,該線程將變成Runnable狀態。

  1. Waiting(無限等待)

一個線程在等待另外一個線程執行一個(喚醒)動做時,該線程進入Waiting狀態。進入這個狀態後是不能自動喚醒的,必須等待另外一個線程調用notify或者notifyAll方法纔可以喚醒。

  1. Timed Waiting(計時等待)

同waiting狀態,有幾個方法有超時參數,調用他們將進入Timed Waiting狀態。這一狀態將一直保持到超時期滿或者接收到喚醒通知。帶有超時參數的經常使用方法有Thread.sleep 、Object.wait。

  1. Teminated(被終止)

由於run方法正常退出而死亡,或者由於沒有捕獲的異常終止了run方法而死亡。

相關文章
相關標籤/搜索