學習Java的多線程知識之前,我們先來了解一下進程和線程的概念,以及他們之間的關系。
進程
基本概念
進程是具有獨立功能的程序在某個數據集合上的一次執行過程。
特點
- 進程是操作系統進行資源分配的基本單位。
- 每個進程都有自己的地址空間,即進程空間。
線程
基本概念
一個進程內部的一個執行單元,它是程序中的一個單一的順序控制流程。
特點
- 自己不擁有系統資源,只擁有一點兒在運行過程中必不可少的資源。與同一個進程下的其他所有線程共享進程所擁有的全部資源。
- 線程是進程中的一個實體,是被操作系統獨立調度的基本單位。
進程和線程的聯系和區別
進程是資源分配的基本單位,線程是調度的基本單位。進程包含線程,線程共用進程的資源。
Java實現多線程
有四種方式:
- 繼承Thread類
- 實現Runnable接口
- 實現Callable接口,并與FutureTask結合使用
- 線程池
繼承Thread類
package com.cc.thread;public class ThreadDemo extends Thread{public ThreadDemo(String name) {super(name);}@Overridepublic void run() {for (int i = 0; i < 10000; i++) {System.out.println(this.getName()+i);}}public static void main(String[] args) {new ThreadDemo("張三").start();new ThreadDemo("李四").start();}}
實現Runnable接口
package com.cc.thread;public class RunableDemo implements Runnable {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public RunableDemo(String name) {super();this.name = name;}@Overridepublic void run() {for (int i = 0; i < 10000; i++) {System.out.println(this.getName()+i);}}public static void main(String[] args) {new Thread(new RunableDemo("張三")).start();new Thread(new RunableDemo("李四")).start();}}
實現Callable接口,并與FutureTask結合使用
package com.cc.thread;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class CallableDemo {public static void main(String[] args) {CallableImpl callableImpl = new CallableImpl();FutureTask<Integer> futureTask = new FutureTask<Integer>(callableImpl);Thread thread = new Thread(futureTask);thread.start();try {int sum = futureTask.get();System.out.println(sum);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}}private static class CallableImpl implements Callable<Integer>{@Overridepublic Integer call() throws Exception {int sum = 0;for (int j = 0; j <= 100; j++) {System.out.println(Thread.currentThread().getName()+":"+j);sum += j;}return sum;}}}
運行上面的代碼,我們發現每次返回的結果都是5050(這么巧的嗎?難道每次call方法瞬間就執行完了,然后再執行的int sum = futureTask.get();),其實如果線程的call方法還未執行完畢,futureTask.get()方法會一直阻塞,直到call()方法執行完畢才能取到返回值。
線程的生命周期
通過查看Thread內部類State的源碼,我們知道線程有6中狀態,分別是:
? ? NEW,
? ? RUNNABLE,
? ? BLOCKED,
? ? WAITING,
? ? TIMED_WAITING,
? ? TERMINATED;
Thread內部類State的源碼
public enum State {/*** Thread state for a thread which has not yet started.*/NEW,/*** Thread state for a runnable thread. A thread in the runnable* state is executing in the Java virtual machine but it may* be waiting for other resources from the operating system* such as processor.*/RUNNABLE,/*** Thread state for a thread blocked waiting for a monitor lock.* A thread in the blocked state is waiting for a monitor lock* to enter a synchronized block/method or* reenter a synchronized block/method after calling* {@link Object#wait() Object.wait}.*/BLOCKED,/*** Thread state for a waiting thread.* A thread is in the waiting state due to calling one of the* following methods:* <ul>* <li>{@link Object#wait() Object.wait} with no timeout</li>* <li>{@link #join() Thread.join} with no timeout</li>* <li>{@link LockSupport#park() LockSupport.park}</li>* </ul>** <p>A thread in the waiting state is waiting for another thread to* perform a particular action.** For example, a thread that has called <tt>Object.wait()</tt>* on an object is waiting for another thread to call* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on* that object. A thread that has called <tt>Thread.join()</tt>* is waiting for a specified thread to terminate.*/WAITING,/*** Thread state for a waiting thread with a specified waiting time.* A thread is in the timed waiting state due to calling one of* the following methods with a specified positive waiting time:* <ul>* <li>{@link #sleep Thread.sleep}</li>* <li>{@link Object#wait(long) Object.wait} with timeout</li>* <li>{@link #join(long) Thread.join} with timeout</li>* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>* </ul>*/TIMED_WAITING,/*** Thread state for a terminated thread.* The thread has completed execution.*/TERMINATED;}
?關于線程狀態的詳細描述和他們之前的相互轉換請參考4 Java線程的狀態及主要轉化方法 · 深入淺出Java多線程
線程方法總結
start | 使線程由新建狀態進入就緒狀態,只能調用一次,否則會報IllegalThreadStateException |
run | 線程執行體,由系統調用 |
isAlive | 新建和死亡狀態會返回false,其他狀態返回true |
interrupt | 設置線程中斷狀態為true |
interrupted | static方法,先返回當前線程中斷狀態,然后設置線程中斷狀態為false |
isInterrupted | 返回當前線程中斷狀態 |
sleep | static native方法,使線程進入阻塞狀態(不會釋放同步鎖) |
currentThread | static方法,該方法返回當前正在使用CPU資源的線程 |
setPriority | final方法,設置線程的優先級,1~10 1最低 10最高 5是默認值 線程的優先級具有繼承性,比如A線程啟動B線程,則A和B的線程優先級是一樣的 |
getPriority | final方法,獲取線程優先級 |
setDaemon | 設置守護線程(也叫服務線程,用于為系統中的對象和線程提供服務,如果都是服務線程,那么JVM結束,垃圾回收線程是守護線程) |
isDaemon | 判斷是否是守護線程 |
join | thread1.join();使當前線程進入阻塞狀態,thread1線程執行完后,再喚醒當前線程 |
yeild | 使當前線程進入就緒狀態 |
wait | Object類的方法,讓當前線程進入阻塞狀態,并且釋放它持有的同步鎖 |
notify | Object類的方法,喚醒一個阻塞狀態的線程 |
notifyAll | Object類的方法,喚醒所有阻塞狀態的線程 |
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
join方法的使用
package com.cc.thread;public class ThreadJoin {public static void main(String[] args) throws InterruptedException {Thread thread1 = new Thread("線程1"){@Overridepublic void run() {for (int i = 0; i < 1000; i++) {System.out.println(Thread.currentThread().getName()+":"+i);}}};thread1.start();thread1.join();for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName()+":"+i);}}}
interrupt、interrupted和isInterrupted的作用和區別
- interrupt設置線程中斷狀態為true
- interrupted先返回當前線程中斷狀態,然后設置線程中斷狀態為false
- isInterrupted返回當前線程中斷狀態
- 下面的demo只用到了sleep方法,wait,join方法類似于sleep
package com.cc.thread;public class InterruptTest {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(){@Overridepublic void run() {for (int i = 0; i < 5; i++) {try {sleep(2000);//線程默認中斷狀態為false,調用sleep方法,或者在sleep的過程中,當中斷狀態為true時,執行sleep會拋出異常interrupt();//設置中斷狀態為true} catch (InterruptedException e) {//拋出異常后中斷狀態自動設置為falseSystem.out.println("出現中斷異常,中斷狀態:"+isInterrupted());}System.out.println("正常執行,中斷狀態:"+isInterrupted());}}};thread.start();}}
package com.cc.thread;public class InterruptTest {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(){@Overridepublic void run() {for (int i = 0; i < 5; i++) {try {sleep(2000);//線程默認中斷狀態為false,調用sleep方法,或者在sleep的過程中,當中斷狀態為true時,執行sleep會拋出異常interrupt();//設置中斷狀態為trueSystem.out.println("interrupted方法:"+interrupted());//此函數首先返回當前的中斷狀態,然后將中斷狀態置為falseSystem.out.println("isInterrupted:"+isInterrupted());} catch (InterruptedException e) {//拋出異常后中斷狀態自動設置為falseSystem.out.println("出現中斷異常,中斷狀態:"+isInterrupted());}System.out.println("正常執行,中斷狀態:"+isInterrupted());}}};thread.start();}}
wait方法的使用
package com.cc.thread;public class ObjectWait {public static void main(String[] args) {try {Thread threadTest = new Thread(){public void run(){System.out.println("執行線程中方法");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}};threadTest.start();synchronized(threadTest){threadTest.wait(); //當線程終止的時候,會調用線程自身的notifyAll()方法}System.out.println("執行到了這里");} catch (InterruptedException e) {e.printStackTrace();}}
}
synchronized
synchronized的用法參考Java中使用同步關鍵字synchronized需要注意的問題 - @ 小浩 - 博客園
synchronized是非公平鎖
synchronized的實現原理參考Java中的鎖——Lock和synchronized - 夏末秋涼 - 博客園
?1,synchronized代碼塊基于進入和退出monitor對象實現。代碼編譯后將monitorenter指令插入同步代碼塊的前面,monitorexit指令插入同步代碼塊的后面,發生異常時也會執行monitorexit指令
2,synchronized方法讀取運行時常量池中方法的?ACC_SYNCHRONIZED?標志來隱式實現的
3,synchronized用的鎖存儲在對象頭中的markword,markword中的鎖標記指向的是monitor對象,
鎖標記位(無鎖01、輕量級鎖00、重量級鎖10、偏向鎖01)
4,monitor對象有兩個隊列(EntryList、WaitSet)以及鎖持有者Owner標記
線程安全的概念
什么是線程安全:在多線程環境下,線程安全的代碼會通過線程同步機制保證各個線程可以正常的正確的執行,不會出現數據污染等意外情況。
什么是線程同步:是指各個線程按照一定的順序執行