多線程

Thread有單繼承侷限性所以不建議使用,但是所有的線程對象一定要通過Thread裏中的star
         t()方法 Runnable使用時可以避免單繼承的侷限,所以建議使用此操作
                 Callable比Runnable唯一的好處是多了返回值的數據


一:進程與線程


概述:幾乎任何的操作系統都支持運行多個任務,通常一個任務就是一個程序,而一個程序就是一個進程。當一個進程運行時,
   內部可能包括多個順序執行流,每個順序執行流就是一個線程。
   進程:進程是指處於運行過程中的程序,並且具有一定的獨立功能。進程是系統進行資源分配和調度的一個單位。當程序進
   入內存運行時,即爲進程。
   進程的三個特點:
1:獨立性:進程是系統中獨立存在的實體,它可以獨立擁有資源,每一個進程都有自己獨立的地址空間,沒有進程本身的運行,
   用戶進程不可以直接訪問其他進程的地址空間。
2:動態性:進程和程序的區別在於進程是動態的,進程中有時間的概念,進程具有自己的生命週期和各種不同的狀態。
3:併發性:多個進程可以在單個處理器上併發執行,互不影響。
   併發性和並行性是不同的概念:並行是指同一時刻,多個命令在多個處理器上同時執行;併發是指在同一時刻,只有一條命
   令是在處理器上執行的,但多個進程命令被快速輪換執行,使得在宏觀上具有多個進程同時執行的效果


線程:
線程是進程的組成部分,一個進程可以擁有多個線程,而一個線程必須擁有一個父進程。線程可以擁有自己的堆棧,自己的程序
   計數器和自己的局部變量,但不能擁有系統資源。它與父進程的其他線程共享該進程的所有資源。
線程的特點:
線程可以完成一定任務,可以和其它線程共享父進程的共享變量和部分環境,相互協作來完成任務。
線程是獨立運行的,其不知道進程中是否還有其他線程存在。
線程的執行是搶佔式的,也就是說,當前執行的線程隨時可能被掛起,以便運行另一個線程。
一個線程可以創建或撤銷另一個線程,一個進程中的多個線程可以併發執行。
二、線程的創建及使用


java使用Thread類代表線程,所有的線程對象都必須是Thread或者其子類的實例,每個線程的作用是完成一定任務,實際上是就是
   執行一段程序流(一段順序執行的代碼)
方案一:繼承Thread類創建線程類
步驟: ① 定義Thread類的子類 並重寫該類的Run方法,該run方法的方法體就代表了該線程需要完成的任務
        ② 創建Thread類的實例,即創建了線程對象
        ③ 調用線程的start方法來啓動線程


class MyThread extends Thread {
private String name;


public MyThread(String name) {
this.name = name;
}


@Override
public void run() {
for (int x = 0; x < 10; x++) {
System.out.println(this.name + "x=" + x);
}
}
}
public class ThreadTest {
public static void main(String[] args) {
MyThread m1 = new MyThread("線程B");
MyThread m2 = new MyThread("線程B");
MyThread m3 = new MyThread("線程C");
        m1.start();
        m1.start();
        m2.start();
        m3.start();
}
}
方案二:實現Runnable接口
 ①定義Runnable接口的實現類,並重寫它的Run方法,run方法同樣是該線程的執行體!
 ②創建Runnable實現類的實例,並將此實例作爲Thread的target創建一個Thread對象,該Thread對象纔是真正的線程對象!
 ③調用start方法啓動該線程
class MyThread implements Runnable {
private String name;


public MyThread(String name) {
this.name = name;
}


@Override
public void run() {
for (int x = 0; x < 10; x++) {
System.out.println(this.name + "x=" + x + Thread.currentThread().getName());
}
}
}


public class ThreadTest {
public static void main(String[] args) {
MyThread m1 = new MyThread("線程B");
Thread th = new Thread(m1,"線程1");
th.start();
}
}
結論:採用Ruunable接口的方式創建多個線程可以共享線程類的實例變量,這是因爲在這種方式下,程序創建的Runnable對象只是線程的target,
      而多個線程可以共享一個target,所以多個線程可以共享一個實例變量 
      通過Runnable實現多線程其實就是將run包裝成線程的執行體,但是目前java無法將任意方法包裝成線程執行體


方案三:使用callable和future創建線程
       從Java5開始,Java提供 Callable接口,Callable接口提供了一個call()方法可以作爲線程執行體,看起來和Runnable很像,但call()方法更強大
       ——call()方法可以有返回值、call()方法可以拋出異常
       Java5提供了Future接口來代表Callable接口的call()方法的返回值,併爲Future接口提供了一個FutureTask實現類,該實現類實現類Future接口,
       也實現了Runnable接口——可以作爲Thread的target。


實現步驟:
①創建Callable接口的實現類,並實現call方法,該call方法會成爲線程執行體,且call方法具有返回值,在創建callable接口的實現類!
②使用FutrueTask類來包裝Callable對象,該FutrueTask封裝類Callable的call方法的返回值
③使用FutrueTask對象作爲Thread的target創建並啓動新線程!
④使用FutrueTask的get方法獲取執行結束後的返回值
class MyThread implements Callable<Integer> {
    int  i = 0;
@Override
public Integer call() throws Exception {
for(;i > 20; i++) {
System.out.println(Thread.currentThread().getName());
}
return i;
}
}


public class ThreadTest {
public static void main(String[] args) throws Exception, ExecutionException {
MyThread m1 = new MyThread();
FutureTask<Integer> ft = new FutureTask<>(m1);
Thread th = new Thread(ft,"線程1");
th.start();
System.out.println(ft.get());
}
}
結論:採取Runnable、Callable的優勢在於——線程類只是實現了Runnable或Callable接口,還可以繼承其它類;在這種方法下,
      多個線程可以共享一個target對象,因此非常適合多個相同線程處理同一份資源的情況,從而將CPU、代碼和數據分開,形參清晰的模型,
      體現了面對對象的編程思想。劣勢在於編程複雜度略高。




線程的命名和取得


從本質上來講線程的運行狀態並不是固定的。所以來講要想確定線程的執行,唯一的區別就在於線程的名稱上。在起名的時候
就應該儘可能的避免重複,或者避免修改名稱
在Thread類中提供可以實現線程名稱的操作。
    構造方法:public Thread(Runnable tagget,String name)
    設置名稱:public final void setName(String name)
    取得名字:public final void getName(String name)
既然線程的執行本身是不確定的狀態,所以如果要取得線程名字的話,那麼唯一能做的就是獲取當前線程的名字
所以在Thread類中提供了這樣的方法:public static Thread currentThread()
如果線程的命名沒有指定那麼它有默認的名字


class MyThread implements Runnable{


@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName());
}


}


public class ThreadTest {
public static void main(String[] args) throws Exception, ExecutionException {
        Thread th = new Thread(new MyThread(),"我的線程7777");
        th.start();
        th.run();
}
}
返回結果
main
我的線程7777


線程一定是依附於進程存在的,但是現在的進程在哪裏哪?
當使用Java命令在jvm上程序執行的時候,那麼都會默認的啓動一個JVM的進程
,所以整個程序一直都在跑在線程的運行機制上。
每一個jvm至少會執行兩個進程,main和gc線程


線程的休眠


class MyThread implements Runnable{


@Override
public void run() {
for(int i = 0;i < 10; i++ ) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("我被中斷段了");
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
}


public class ThreadTest {
public static void main(String[] args) throws Exception, ExecutionException {
        Thread th = new Thread(new MyThread(),"我的線程7777");
        th.start();
        Thread.sleep(2000);
        th.interrupt();
}
}


輸出
我的線程7777
我被中斷段了
java.lang.InterruptedException: sleep interrupted
我的線程7777
at java.lang.Thread.sleep(Native Method)
at com.imnu.th.MyThread.run(ThreadTest.java:13)
at java.lang.Thread.run(Unknown Source)
我的線程7777


線程的中斷一定是另一個線程將其中斷的




線程的優先級
從理論上來講越高的線程越有可能先執行,而在Thread類裏而定義有一下的優先級的操作
  設置優先級 public final void setProirity
  取得優先級 public final void getProirity
1.線程的名字,Thread.currentThread取得當前線程
2.線程的休眠是有先後順序的
3.理論上線程的優先級越高越有可能先執行。


重點:儘管JDK有十個優先級,但是與大多數的操作系統是不能很好的映射,唯一可以移植方法是調整優先級的時候,
      只有MAX_PRIORITY,NORM_PRIORITY,MIN_PRIORITY
三種機制






加入同步代碼的執行速度慢了,而且不像沒有同步那時候那樣,多個線程會一起進入到方法中
異步的速度要
class MyThread implements Runnable {
private int ticket = 5;


@Override
public void run() {
for (int i = 0; i < 100; i++) {
synchronized (this) {
if (this.ticket > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "ticket" + this.ticket--);
}
}
}
}
}


public class ThreadTest {
public static void main(String[] args) throws Exception, ExecutionException {
MyThread th = new MyThread();
Thread th1 = new Thread(th, "a");
Thread th2 = new Thread(th, "b");
Thread th3 = new Thread(th, "b");
th1.setPriority(Thread.MAX_PRIORITY);
th2.setPriority(Thread.MIN_PRIORITY);
th1.start();
th2.start();
th3.start();
}
}















發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章