1. 程式人生 > >java多線程的實現

java多線程的實現

art 處理 lock urn 將不 模式 應用 所有 -h

線程和進程之間的關系

? 線程時在進程基礎之上創建並使用的更小的程序單元,所以線程依賴於進行的支持。線程的啟動速度要比進程快上很多,高並發處理的時候,線程的性能要高於進程

多線程實現

任何情況下,只要定義了多線程,那麽多線程的啟動永遠只有一種方案:Thread類的start()方法

不要調用Thread類話或者Runnable對象的run方法。直接調用run方法,只會執行同一個線程中的任務,而不會啟動新的線程。應該調用Thread.start方法,這個run方法將創建執行run方法的新線程。(摘自java核心技術)

繼承Thread類

? 定義多線程主體類,繼承Thread類,只有重寫run()方法,多線程要執行的功能應該在run()方法中定義

? start()方法最終執行的時run()方法中的功能,但是如果直接使用run()方法的話,將不能開啟多線程(線程順序執行,而不是交替執行)

public class MyThread extends Thread {
@Override
public void run() {
//多線程功能定義
}
}
?

查看Thread的start()源碼

/**
* @exception IllegalThreadStateException if the thread was already
* started.
* @see #run()
* @see #stop()
*/
public synchronized void start() {

if (threadStatus != 0)
throw new IllegalThreadStateException();


group.add(this);
?
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {

}
}
}

每個線程類的對象只允許啟動一次,如果重復啟動,會報IllegalThreadStateException異常

技術分享圖片

實現Runnable接口

? Runnable接口源碼

@FunctionalInterface
public interface Runnable {
/**
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}

為函數式編程,可以使用jdk1.8的lamda表達式

傳統實現

public class MyThread1 implements Runnable {
?
/**
* title
*/
private String title;
?
public MyThread1(String title) {
this.title = title;
}
?
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(this.title + "運行,i=" + i);
}
}
}

lamda表達式

       Runnable runnable = ()->{
for (int i = 0; i < 10; i++) {
System.out.println("線程開始運行");
}
};
new Thread(runnable).start();

啟動:

       final MyThread1 thread1 = new MyThread1("線程A");
final MyThread1 thread2 = new MyThread1("線程B");
final MyThread1 thread3 = new MyThread1("線程C");
?
new Thread(thread1).start();
new Thread(thread2).start();
new Thread(thread3).start();

WARNING:

線程資源必須通過線程池提供,不允許在應用中自行顯式創建線程。

說明:使用線程池的好處是減少在創建和銷毀線程上所花的時間以及系統資源的開銷,解決系統資源不足的問題。如果不適用線程池,有可能造成系統創建大量同類線程而導致消耗完內存或者"過度切換的問題"。

應該將要並行運行的任務與運行機制解耦合。如果有很多任務,要為每個任務創建一個獨立的線程所付出的代價太大了,可以使用線程池來解決這個問題。(摘自java核心技術)

線程池創建線程示例:

ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build();
ExecutorService singleThreadPool = new ThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECONDS,new
LinkedBlockingDeque<Runnable>(1024),namedThreadFactory,new ThreadPoolExecutor.AbortPolicy());
singleThreadPool.execute(()-> System.out.println(Thread.currentThread().getName()));
singleThreadPool.shutdown();

Thread和Runnable的關系

技術分享圖片

多線程的設計之中,使用了代理設計模式的結構,用戶自定義的線程主體知識負責項目核心功能的實現,而所有的輔助實現全部交由Thread類來實現

多線程開發的本質上是在於多個線程可以進行同一資源的搶占,那麽Thread主要描述的是線程,而資源的描述是通過Runnable完成的。

技術分享圖片

多線程資源訪問實現賣票程序

public class MyThread implements Runnable {
?
private int ticket = 5;
?
@Override
public void run() {
//多線程功能定義
for (int i = 0; i < 100; i++) {
if (this.ticket > 0) {
System.out.println("賣票,ticket=" + this.ticket--);
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
MyThread mt = new MyThread();
new Thread(mt).start();
new Thread(mt).start();
new Thread(mt).start();
}
}

Callable實現多線程

使用Callable實現多線程的好處在於在線程執行完畢之後可以獲取一個返回值,同時支持泛型

技術分享圖片

範例:使用Callable實現多線程處理

public class MyThread implements Callable<String > {
?
@Override
public String call() throws Exception {
for (int i = 0; i < 10; i++) {
System.out.println("********* 線程執行、i = "+i);
}
return "線程執行完畢";
}
}
?
public class ThreadDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> task = new FutureTask<>(new MyThread());
new Thread(task).start();
System.out.println("【線程返回的數據】" + task.get());
}
}

線程運行狀態

? 對於多線程的開發而言,編寫程序的過程之中總是按照:定義線程主體類,而後通過Thread類進行線程的啟動,但不以為者你調用了start()方法,線程就已經開發啟動了,因為整體的線程處理有自己的一套運行的狀態。

技術分享圖片

java多線程的實現