多線程
在講線程之前,我們應該先了解一下什麼是進程?
進程:系統可以進行獨立調配並且它是一個不可分割 獨立單元
例如(我們手機或者電腦後臺運行的軟件,客戶端等等,它們就是進程)
線程:線程是進程中一個獨立的單元,線程有自己的堆棧和局部變量,但線程之間沒有單獨的地址空間。
例如:(我們的電腦管家可以進行殺毒和清理垃圾,其中的殺毒和清理垃圾功能就可以看做事線程)
多線程:像上面所說的電腦管家,當我們同時執行清理垃圾和殺毒功能,雖然表面看起來是可以同步進行的,但實際不是同步進行的,只是每個線程在搶佔CPU的執行權,這就是多線程。
多線程的意義:爲了提高CPU的使用率,
線程之間都在搶佔CPU的執行權,而且多線程的執行是隨機的
要想實現多線程程序,需要開啓進程,開啓進程就需要創建系統資源,但是隻有c/c++可以創建資源,所我們我們可以在底層利用c創建好的系統資源來實現
併發和並行的區別:
併發是指同一個時間點,物理邏輯上的
並行指的是同一個時間段。
讓我們來看看多線程的實現:
首先我們需要創建一個子類去實現Thread類,並且要重寫該類的run方法
package com.westos.Thread;
public class MyThread extends Thread{
/*public MyThread(String name) {
super(name);
}*/
public void run() {
for(int x=0;x<100;x++) {
System.out.println(getName()+":"+x);
}
}
}
創建一個實現類去實現多線程,這是給線程設置名字的兩種方式:
package com.westos.Thread;
public class ThreadDome {
/**
* @param args
* 給線程設置名字的兩種方式
* 使用方式1時:可以不在MyThread類中添加無參構造,因爲系統默認訪問無參構造
* 當你使用第二種方式時,就必須要添加有參構造了,否則就會報錯
*/
public static void main(String[] args) {
//方式1:無參+setName()方法
//創建MyThread類對象
MyThread mt=new MyThread();
MyThread mt2=new MyThread();
//setName方法
mt.setName("迪麗熱巴");
mt2.setName("井傑");
//開始運行
mt.start();
mt2.start();
//方式2:直接MyThread類的有參構造
/*//創建MyThread類對象
MyThread mt=new MyThread("迪麗熱巴");
MyThread mt2=new MyThread("井傑");
//開始運行
mt.start();
mt2.start();
*/
}
}
線程的一些方法:
等待該線程終止:
public final void join()throws InterruptedException等待該線程終止。
返回正在執行的線程:
public static Thread currentThread()返回對當前正在執行的線程對象的引用。
package com.westos.Thread01;
public class ThreadJoin extends Thread{
public void run() {
for(int x=0;x<100;x++) {
System.out.println(getName()+":"+x);
}
}
}
package com.westos.Thread01;
public class ThreadDome {
public static void main(String[] args) {
//創建三個ThreadJoin類對象
ThreadJoin tj=new ThreadJoin();
ThreadJoin tj2=new ThreadJoin();
ThreadJoin tj3=new ThreadJoin();
//設置名字
tj.setName("劉備");
tj2.setName("張飛");
tj3.setName("關羽");
tj.start();
//public final void join()throws InterruptedException等待該線程終止。
try {
tj.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
tj2.start();
tj3.start();
/*//public static Thread currentThread()返回對當前正在執行的線程對象的引用。
System.out.println(Thread.currentThread().getName());
運行的結果是:main(該方法返回的是正在執行的主線程,而tj和tj2是主線程的兩個子線程)
*/
}
}
暫停線程:
public static void yield()暫停當前正在執行的線程對象,並執行其他線程
package com.westos.Thread02;
public class Threadyield extends Thread{
public void run() {
for(int x=0;x<100;x++) {
System.out.println(getName()+":"+x);
}
//public static void yield()暫停當前正在執行的線程對象,並執行其他線程。
Thread.yield();
}
}
package com.westos.Thread02;
public class YieldDome {
public static void main(String[] args) {
//創建Threadyield類對象
Threadyield ty=new Threadyield();
Threadyield ty2=new Threadyield();
//設置名字
ty.setName("蜘蛛俠");
ty2.setName("鋼鐵俠");
//開始運行
ty.start();
ty2.start();
}
}
守護線程:
public final void setDaemon(boolean on)將該線程標記爲守護線程或用戶線程
package com.westos.Thread03;
public class ThreadsetDaemon extends Thread{
public void run() {
for(int x=0;x<100;x++) {
System.out.println(getName()+":"+x);
}
}
}
package com.westos.Thread03;
/**
* @author 傑哥
*調用setDaemon方法時,必須有主線程一起啓動,否則無法編譯
*/
public class setDaemonDome {
public static void main(String[] args) {
//創建ThreadsetDaemon類對象
ThreadsetDaemon td=new ThreadsetDaemon();
ThreadsetDaemon td2=new ThreadsetDaemon();
td.setName("雅妃");
td2.setName("美杜莎");
//public final void setDaemon(boolean on)將該線程標記爲守護線程或用戶線程。
//當正在運行的線程都是守護線程時,Java 虛擬機退出。
//該方法必須在啓動線程前調用。 值爲true時表示正常
td.setDaemon(true);
td2.setDaemon(true);
//啓動線程
td.start();
td2.start();
Thread.currentThread().setName("蕭炎");
for(int i=0;i<5;i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
休眠:
public static void sleep(long millis) throws InterruptedException
在指定的毫秒數內讓當前正在執行的線程休眠(暫停執行),
package com.westos.Thread03;
/**
* @author 傑哥
*調用setDaemon方法時,必須有主線程一起啓動,否則無法編譯
*/
public class setDaemonDome {
public static void main(String[] args) {
//創建ThreadsetDaemon類對象
ThreadsetDaemon td=new ThreadsetDaemon();
ThreadsetDaemon td2=new ThreadsetDaemon();
td.setName("雅妃");
td2.setName("美杜莎");
//public final void setDaemon(boolean on)將該線程標記爲守護線程或用戶線程。
//當正在運行的線程都是守護線程時,Java 虛擬機退出。
//該方法必須在啓動線程前調用。 值爲true時表示正常
td.setDaemon(true);
td2.setDaemon(true);
//啓動線程
td.start();
td2.start();
Thread.currentThread().setName("蕭炎");
for(int i=0;i<5;i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
package com.westos.Thread04;
public class ThreadsleepDome {
public static void main(String[] args) {
//創建對象
ThreadSleep ts=new ThreadSleep();
ThreadSleep ts2=new ThreadSleep();
ts.setName("張三");
ts2.setName("李四");
ts.start();
ts2.start();
}
}
stop():直接停止線程執行
interrupt():中斷線程。
package com.westos.Thread05;
public class ThreadStopInterrupt extends Thread{
public void run() {
System.out.println("程序開始了...");
//睡眠10秒
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// e.printStackTrace();
System.out.println("程序出現中斷異常...");
}
System.out.println("程序結束了...");
}
}
package com.westos.Thread05;
public class StopInterruptDome {
public static void main(String[] args) {
ThreadStopInterrupt tsi=new ThreadStopInterrupt();
tsi.start();
try {
tsi.sleep(3000);
//表示停止
// tsi.stop();
//中斷線程
tsi.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
前面我們學習了多線程的實現,除了上面繼承Thread類的這種方式呢,還有一種實現Runnable接口的方法,它也可以進行多線程的實現,但是其中的一些方法發生了改變,需要我們注意:
package com.westos.Runable;
/**
* @author 傑哥
*實現多線程的第二種方式:實現Runable接口
*/
public class RunnableDome implements Runnable{
public void run() {
for(int x=0;x<100;x++) {
//因爲這是第二種方式,不是之前的繼承Thread方式,所以不能直接調用getName方法
//Thread.currentThread()返回的是正在運行的線程
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}
package com.westos.Runable;
public class RunnableTest {
public static void main(String[] args) {
//創建RunableDome類對象
RunnableDome rd=new RunnableDome();
/**
* Thread(Runnable target, String name) 分配新的 Thread 對象。
* 這是Thread類有關Runnable接口的一種構造方法
*/
Thread t1=new Thread(rd,"楊過");
Thread t2=new Thread(rd,"小龍女");
t1.start();
t2.start();
}
}