程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> java多線程系列1--線程實現與調度,java多線程1--線程

java多線程系列1--線程實現與調度,java多線程1--線程

編輯:JAVA綜合教程

java多線程系列1--線程實現與調度,java多線程1--線程


java的重要功能之一就是內部支持多線程,這一系列文章將詳細剖析java多線程的基礎知識

多線程概述

多線程引入

  • 程序只有一個執行流程,所以這樣的程序就是單線程程序。
  • 假如一個程序有多條執行流程,那麼,該程序就是多線程程序。

進程:正在運行的程序,是系統進行資源分配和調用的獨立單位。每一個進程都有它自己的內存空間和系統資源。

線程:是進程中的單個順序控制流,是一條執行路徑。一個進程如果只有一條執行路徑,則稱為單線程程序。

一個進程如果有多條執行路徑,則稱為多線程程序。

Java程序運行原理

java 命令會啟動 java 虛擬機,啟動 JVM,等於啟動了一個應用程序,也就是啟動了一個進程。該進程會自動啟動一個 “主線程” ,然後主線程去調用某個類的 main 方法。所以 main方法運行在主線程中。在此之前的所有程序都是單線程的。

java虛擬機是多線程的,因為除了主線程外,還有垃圾回收線程

多線程實現方案

方式1:繼承Thread類
步驟
1、自定義類MyThread繼承Thread類。
2、MyThread類裡面重寫run()
3、創建對象
4、啟動線程

下面的代碼:

/*
 * 該類要重寫run()方法,為什麼呢?
 * 不是類中的所有代碼都需要被線程執行的。
 * 而這個時候,為了區分哪些代碼能夠被線程執行,java提供了Thread類中的run()用來包含那些被線程執行的代碼。
 */
public class MyThread extends Thread {
    @Override
    public void run() {
        // 一般來說,被線程執行的代碼肯定是比較耗時的。所以我們用循環改進
        for (int x = 0; x < 300; x++) {
            System.out.println(x);
        }
    }
}
public class MyThreadDemo {
    public static void main(String[] args) {
        // 創建兩個線程對象
        MyThread my1 = new MyThread();
        MyThread my2 = new MyThread();
        my1.start();
        my2.start();
    }
}

步驟:

1、自定義類MyRunnable實現Runnable接口
2、重寫run()方法
3、創建MyRunnable類的對象
4、創建Thread類的對象,並把C步驟的對象作為構造參數傳遞

public class MyRunnable implements Runnable {
 
    @Override
    public void run() {
        for (int x = 0; x < 100; x++) {
            // 由於實現接口的方式就不能直接使用Thread類的方法了,但是可以間接的使用
            System.out.println(Thread.currentThread().getName() + ":" + x);
        }
    }
}
/*
 * 方式2:實現Runnable接口
 * 步驟:
 *         A:自定義類MyRunnable實現Runnable接口
 *         B:重寫run()方法
 *         C:創建MyRunnable類的對象
 *         D:創建Thread類的對象,並把C步驟的對象作為構造參數傳遞
 */
public class MyRunnableDemo {
    public static void main(String[] args) {
        // 創建MyRunnable類的對象
        MyRunnable my = new MyRunnable();
 
        // 創建Thread類的對象,並把C步驟的對象作為構造參數傳遞
        // Thread(Runnable target)
        Thread t1 = new Thread(my);
        Thread t2 = new Thread(my);
        t1.setName("zhangsan");
        t2.setName("lisi");
 
        // Thread(Runnable target, String name)
        Thread t1 = new Thread(my, "zhangsan");
        Thread t2 = new Thread(my, "lisi");
 
        t1.start();
        t2.start();
    }
}

實現接口方式的好處:

1. 可以避免由於Java單繼承帶來的局限性。

2. 適合多個相同程序的代碼去處理同一個資源的情況,把線程同程序的代碼,數據有效分離,較好的體現了面向對象的設計思想。

獲取和設置線程名稱

Thread類的基本獲取和設置方法:

public final String getName() public final void setName(String name)

其實通過構造方法也可以給線程起名字

如何獲取main方法所在的線程名稱呢?

public static Thread currentThread()

這樣就可以獲取任意方法所在的線程名稱

示例代碼如下:

public class MyThread extends Thread {
    public MyThread() {
    }
    
    public MyThread(String name){
        super(name);
    }
    @Override
    public void run() {
        for (int x = 0; x < 100; x++) {
            System.out.println(getName() + ":" + x);
        }
    }
}
public class MyThreadDemo {
    public static void main(String[] args) {
        // 創建線程對象
        //無參構造+setXxx()
         MyThread my1 = new MyThread();
         MyThread my2 = new MyThread();
        // 調用方法設置名稱
         my1.setName("zhangsan");
         my2.setName("lisi");
         my1.start();
         my2.start();
        
        //帶參構造方法給線程起名字
         MyThread my1 = new MyThread("zhangsan");
         MyThread my2 = new MyThread("lisi");
         my1.start();
         my2.start();
        
        //我要獲取main方法所在的線程對象的名稱,該怎麼辦呢?
        //public static Thread currentThread():返回當前正在執行的線程對象
        System.out.println(Thread.currentThread().getName());
    }
}

線程調度

假如我們的計算機只有一個 CPU,那麼 CPU 在某一個時刻只能執行一條指令,線程只有得到 CPU時間片,也就是使用權,才可以執行指令。那麼Java是如何對線程進行調用的呢?

線程有兩種調度模型:

  • 分時調度模型 所有線程輪流使用 CPU 的使用權,平均分配每個線程占用 CPU 的時間片
  • 搶占式調度模型 優先讓優先級高的線程使用 CPU,如果線程的優先級相同,那麼會隨機選擇一個,優先級高的線程獲取的 CPU 時間片相對多一些。

Java使用的是搶占式調度模型。

public final int getPriority() public final void setPriority(int newPriority)

示例代碼如下:

public class ThreadPriority extends Thread {
    @Override
    public void run() {
        for (int x = 0; x < 100; x++) {
            System.out.println(getName() + ":" + x);
        }
    }
}
/*
 *         public final int getPriority():返回線程對象的優先級
 * 如何設置線程對象的優先級呢?
 *         public final void setPriority(int newPriority):更改線程的優先級。 
 * 
 * 注意:
 *         線程默認優先級是5。
 *         線程優先級的范圍是:1-10。
 *         線程優先級高僅僅表示線程獲取的 CPU時間片的幾率高,但是要在次數比較多,或者多次運行的時候才能看到比較好的效果。
 *         
 * 
 */
public class ThreadPriorityDemo {
    public static void main(String[] args) {
        ThreadPriority tp1 = new ThreadPriority();
        ThreadPriority tp2 = new ThreadPriority();
        ThreadPriority tp3 = new ThreadPriority();
 
        tp1.setName("zhangsan");
        tp2.setName("lisi");
        tp3.setName("wangwu");
 
        // 獲取默認優先級
        System.out.println(tp1.getPriority());
        System.out.println(tp2.getPriority());
        System.out.println(tp3.getPriority());
 
        // 設置線程優先級
        // tp1.setPriority(100000);
        
        //設置正確的線程優先級
        tp1.setPriority(10);
        tp2.setPriority(1);
        tp1.start();
        tp2.start();
        tp3.start();
    }
}

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved