以前大家寫的都是單一執行緒的程序,全是在main函數中呼叫方法,可以清楚的看到它的效率是特別低的,就像python中使用單線程取爬一個網站,可以說能讓你等的吐血,因為數據量實在太大了,今天我們就來看看java的並發編程多線程的學習
建立一個執行緒可以有多種方法,例如繼承Thread類,實作Runnable介面......下面我們來詳細的看看所建立的方法
為什麼繼承
Thread
可以直接呼叫start()
方法啟動執行緒呢,因為start()
本身就是Thread的方法,也就是繼承了Thread的start()方法,因此這個類別的物件可以呼叫start()啟動執行緒
//继承Threadpublic class MyThread extends Thread { public void run() {for (int i = 0; i < 10; i++) { System.out.println(this.getName()+"正在跑"); } } }public class Test{public static void main(String[] args) { Mythread t1=new MyThread(); //创建对象t1.start(); //启动线程} }
注意: 繼承
Thread
類的創建方法一個對像只能創建一個線程,並不能多個線程共用一個對象,只能一個線程對應一個對象,因此讓我們來看看實作Runnable
介面的類別來實作多個執行緒共用同一個物件
//实现Runnable接口public class Demo implements Runnable { @Overridepublic void run() {for(int i=0;i<10;i++) { System.out.println(Thread.currentThread().getName()+"正在跑"); } } }//测试类public class Test{public static void main(String[] args) { Demo d=new Demo(); //创建对象Thread thread1=new Thread(d); //为对象创建一个线程Thread thread2=new Thread(d); //创建另外一个线程//同时启动两个线程thread1.start(); thread2.start(); } }
從上面可以清楚的看到實作
Runnable
介面的類別一個物件可以供多個執行緒共享,不像繼承Thread類別只為一個執行緒使用
直接在
main
方法中創建,如果創建的普通類別的物件在外面,那麼必須是final修飾,可以實現多個執行緒同時共享一個對象,這個和實作Runnable
介面一樣,這時候就要控制同步條件了,如果在run方法中定義對象,那麼,就是一個執行緒對應一個物件,這個就和繼承Thread類別一樣的效果。所以可以依條件自由選擇
//普通的一个类public class Simple {public void display() {for(int i=0;i<10;i++) { System.out.println(Thread.currentThread().getName()+"正在跑"); } } }//线程测试类public class Test {public static void main(String[] args) { //如果在外面必须使用final,当然也可以直写在run方法中,不过写在外面可以实现多个线程共享一个对象//写在run方法中当前对象只能为一个线程使用,和继承Thread类一样的效果final Simple simple=new Simple(); //下面创建使用同一个对象创建同两个线程,实现多个线程共享一个对象,和实现Runnable接口一样的效果Thread t1=new Thread(){public void run() { simple.display(); }; }; Thread t2=new Thread(){public void run() { simple.display(); }; }; //启动这两个线程t1.start(); t2.start(); }}
static void sleep(long mils)
使正在運行的執行緒休眠mils毫秒,但這裡需要注意的是如果執行緒加了鎖,那麼使執行緒休眠並不會釋放鎖定
String getName()
得到執行緒的名稱,上面的程式已經使用了這個方法
void setName(String name)
設定正在執行的執行緒的名字為name
##start()
啟動線程,線程的創建並不意味著線程的啟動,只有呼叫start()方法線程才是真正的開始運行
long getId()
傳回執行緒的識別碼
使用
run()
執行緒執行的程式碼都放在run()方法中,在run方法中的呼叫是有順序的,都是依照程式執行的順序開始執行
以下使用上面的方法建立一個實例#
//线程的类,继承Threadpublic class MyThread1 extends Thread {public void run() { // 重载run方法,并且在其中写线程执行的代码块for (int i = 0; i < 10; i++) {// 获取线程的id和nameSystem.out.println("Thread-Name: " + this.getName() + " Thread-id: " + this.getId());try {this.sleep(1000); // 线程休眠1秒} catch (InterruptedException e) { e.printStackTrace(); } } } }//线程测试的类public class Test {public static void main(String[] args) { MyThread1 t1 = new MyThread1(); // 创建线程t1.setName("第一个线程"); // 设置线程的名字MyThread1 t2 = new MyThread1(); t2.setName("第二个线程"); t1.start(); // 启动线程,开始运行t2.start(); } }
使用
void join()
等待該執行緒終止才能執行其他的執行緒
void join(long mils)
等待該執行緒的時間為mils毫秒,一旦過了這個時間其他執行緒正常執行
//线程类public class MyThread1 extends Thread {public void run() { // 重载run方法,并且在其中写线程执行的代码块for (int i = 0; i < 10; i++) {// 获取线程的id和nameSystem.out.println("Thread-Name: " + this.getName() + " Thread-id: " + this.getId());try {this.sleep(1000); // 线程休眠1秒} catch (InterruptedException e) { e.printStackTrace(); } } } }//测试类public class Test {public static void main(String[] args) { MyThread1 t1 = new MyThread1(); // 创建线程t1.setName("第一个线程"); // 设置线程的名字t1.start(); // 启动线程,开始运行try { t1.join(); //阻塞其他线程,只有当这个线程运行完之后才开始运行其他的线程} catch (InterruptedException e) { e.printStackTrace(); }for (int i = 0; i < 10; i++) { System.out.println("主线程正在运行"); } } }//输出结果/*Thread-Name: 第一个线程 Thread-id: 9Thread-Name: 第一个线程 Thread-id: 9Thread-Name: 第一个线程 Thread-id: 9Thread-Name: 第一个线程 Thread-id: 9Thread-Name: 第一个线程 Thread-id: 9Thread-Name: 第一个线程 Thread-id: 9Thread-Name: 第一个线程 Thread-id: 9Thread-Name: 第一个线程 Thread-id: 9Thread-Name: 第一个线程 Thread-id: 9Thread-Name: 第一个线程 Thread-id: 9主线程正在运行主线程正在运行主线程正在运行主线程正在运行主线程正在运行主线程正在运行主线程正在运行主线程正在运行主线程正在运行主线程正在运行 */
使用
得到目前執行緒優先權
# #getPriority()
改變執行緒的優先權(0-10)預設的是5,優先權越高取得cpu資源的幾率就會越高
#setPriority(int num)
//线程类public class MyThread1 extends Thread {public void run() { // 重载run方法,并且在其中写线程执行的代码块for (int i = 0; i < 10; i++) {// 获取线程的id和nameSystem.out.println("Thread-Name: " + this.getName() + " Thread-id: " + this.getId());try {this.sleep(1000); // 线程休眠1秒} catch (InterruptedException e) { e.printStackTrace(); } } } }//测试类public class Test {public static void main(String[] args) { MyThread1 t1 = new MyThread1(); // 创建线程t1.setName("第一个线程"); // 设置线程的名字MyThread1 t2 = new MyThread1(); t2.setName("第二个线程"); t2.setPriority(8); //设置第二个线程的优先级为8,第一个线程的优先级为5(是默认的)t1.start(); t2.start(); } }/* * 从上面的运行结果可以看出大部分的第二个线程都是在第一个线程之前开始执行的,也就是说优先级越高获得cpu执行的几率就越大 * /
isDaemon ()是否設定為守護線程,如果設定為守護線程,那麼主線程銷毀守護線程也會隨之銷毀
##使用
//测试类public class MyThread1 extends Thread {public void run() { // 重载run方法,并且在其中写线程执行的代码块for (int i = 0; i < 10; i++) {// 获取线程的id和nameSystem.out.println("Thread-Name: " + this.getName() + " Thread-id: " + this.getId());try { Thread.sleep(1000); //休眠一秒,方便主线程运行结束} catch (InterruptedException e) { e.printStackTrace(); } } } }public class Test {public static void main(String[] args) { MyThread1 t1 = new MyThread1(); // 创建线程t1.setName("第一个线程"); // 设置线程的名字t1.setDaemon(true); t1.start();for (int i = 0; i < 1; i++) { System.out.println(i); } } }//结果:/* 0123456789Thread-Name: 第一个线程 Thread-id: 9*//* * 从上面的结果可以看出,一旦主线程结束,那么守护线程就会自动的结束 *- #setDaemon(boolean)
判斷是否為守護執行緒
以上是Thread的定義與常用方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!