主線程:執行主方法的線程,就叫做主線程
單線程程序:程序從mani開始從上到下依次運行
程序從main方法開始運行,JVM運行main方法,會找操作系統
開闢一條通向cpu的執行路徑,cpu可以通過這條路徑來執行main方法
這條路徑有一個名字叫主(main)線程
瞭解更多Java知識,獲取原視頻,源碼,學習交流,那就加入小編的學習交流群吧!616 959 444
創建線程方式一繼承Thread類
實現步驟:
1.創建Thread類的子類
2.重寫Thread類中的run方法,設置線程的任務
3.創建Thread類的子類對象
4.調用Thread類中的start方法開啟一個新的線程,執行run方法
使該線程開始執行;Java 虛擬機調用該線程的 run 方法。
結果是兩個線程併發地運行;當前線程(main線程)和另一個線程(執行 run 方法的線程)。
多次啟動一個線程是非法的。特別是當線程已經結束執行後,不能再重新啟動。
打印的結果出現了隨機性:
開啟兩個線程,對於cpu就選擇權利
喜歡誰,就執行誰,所以就出現了隨機性結果
瞭解更多Java知識,獲取原視頻,源碼,學習交流,那就加入小編的學習交流群吧!616 959 444
線程的名稱:
主線程:"main"
開啟的其它線程的名稱:"Thread-0","Thread-1"....
獲取線程的名稱
1.Thread類中的方法getName
String getName() 返回該線程的名稱。
2.Thread類中的靜態方法,獲取當前正在執行的線程
static Thread currentThread() 返回對當前正在執行的線程對象的引用。
設置線程的名稱:
1.Thread類中的方法setName(String name)
void setName(String name) 改變線程名稱,使之與參數 name 相同。
2.子類添加帶參構造,調用父類Thread類的帶參構造方法,傳遞線程的名稱,讓父類給線程起名字(讓父親給兒子起名字)
Thread(String name) 分配新的 Thread 對象。
創建線程方式—實現Runnable接口
實現步驟:
1.創建Runnable接口的實現類
2.重寫Runnable接口中的run方法,設置線程任務
3.創建Runnable接口的實現類對象
4.創建Thread類對象,構造方法中傳入Runnable接口的實現類
Thread(Runnable target) 分配新的 Thread 對象。
5.調用Thread類中的方法start,開啟線程執行run方法
實現Runnable的好處
1.避免了類繼承Thread類之後,無法繼承其它的類(單繼承的侷限性)
2.把設置線程任務,和開啟線程進行解耦,增強了擴展性
實現類的作用:就是設置線程任務
Thread類的作用:開啟線程
好處:傳遞不同的實現類,實現類重寫的方法不一樣,可以調用不同的方法
線程的匿名內部類使用
匿名:沒有名字
內部類:寫在其他類內部的類(成員位置:成員內部類,局部位置(方法中):局部內部類)
匿名內部類的格式:
new 父類/接口(){
重寫父類/接口中的方法;
};
多線程的父類:
Thread
Runnable
new Thread(){
//重寫run方法,設置線程任務
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
瞭解更多Java知識,獲取原視頻,源碼,學習交流,那就加入小編的學習交流群吧!616 959 444
以上一堆代碼就是一個創建子類重寫父類方法的過程
相當於: new MyThread().start();
程序出現了線程安全問題:賣了重複的票和不存在的票
解決方案:
第一種方式:可以使用同步代碼塊
synchronized(鎖對象){
產生安全問題的代碼;
訪問了共享數據的代碼;
}
注意:
必須要保證多個線程使用的是同一個鎖對象
//在成員位置上創建一個鎖對象(保證唯一)
Object obj = new Object();
@Override
public void run() {
//讓賣票重複執行
while(true){
* 同步代碼塊
* 程序會頻繁的判斷鎖,獲取鎖,釋放鎖,所以會降低速度
synchronized (obj) {
if(ticket>0){
//為了提高安全問題的概率,讓程序睡眠
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//賣票ticket--
System.out.println(Thread.currentThread().getName()+"...賣第"+ticket--+"張票");
}
}
}
}
瞭解更多Java知識,獲取原視頻,源碼,學習交流,那就加入小編的學習交流群吧!616 959 444
程序出現了線程安全問題:賣了重複的票和不存在的票
解決方案:
第二種方式:同步方法
使用步驟:
1.把可能出現安全問題的代碼抽取到一個方法中
2.把方法增加一個關鍵字synchronized
修飾符 synchronized 返回值類型 方法名(參數){
可能出現安全問題的代碼;
訪問了共享數據的代碼;
}
同步方法使用的鎖對象是什麼?
使用的就是本類對象new RunnableImpl()-->叫this
靜態的同步方法,使用時什麼鎖對象?
使用的是本類對象的class屬性(反射)
RunnableImpl.class
*@Override
public void run() {
//讓賣票重複執行
while(true){
payTicket2();
}
}
* 靜態的同步方法
public static synchronized void payTicket2(){
synchronized (RunnableImpl.class) {
if(ticket>0){
//為了提高安全問題的概率,讓程序睡眠
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//賣票ticket--
System.out.println(Thread.currentThread().getName()+"...賣第"+ticket--+"張票");
}
}
}
* 抽取出一個同步方法
* 快捷鍵:alt+shift+m
public ynchronized void payTicket1() {
synchronized (this) {
//System.out.println(this);//cn.itcsat.demo10.RunnableImpl@67064
if(ticket>0){
//為了提高安全問題的概率,讓程序睡眠
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//賣票ticket--
System.out.println(Thread.currentThread().getName()+"...賣第"+ticket--+"張票");
}
}
}
程序出現了線程安全問題:賣了重複的票和不存在的票
*
* 解決方案:
* 第三種方式:使用Lock接口,JDK1.5之後出現的
*
* java.util.concurrent.locks.Lock接口
* 方法:
* void lock() 獲取鎖。
* void unlock() 釋放鎖。
* 接口的實現類:ReentrantLock
*
* 實現步驟:
* 1.在成員位置創建一個Lock接口的實現類對象ReentrantLock
* 2.在可能出現線程安全問題的代碼前,調用lock方法獲取鎖
* 3.在可能出現線程安全問題的代碼後,調用unlock方法釋放鎖
*
*1.在成員位置創建一個Lock接口的實現類對象ReentrantLock
瞭解更多Java知識,獲取原視頻,源碼,學習交流,那就加入小編的學習交流群吧!616 959 444
Lock l = new ReentrantLock();
@Override
public void run() {
//讓賣票重複執行
while(true){
//2.在可能出現線程安全問題的代碼前,調用lock方法獲取鎖
l.lock();
if(ticket>0){
//為了提高安全問題的概率,讓程序睡眠
try {
Thread.sleep(10);
//賣票ticket--
System.out.println(Thread.currentThread().getName()+"...賣第"+ticket--+"張票");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//3.在可能出現線程安全問題的代碼後,調用unlock方法釋放鎖
l.unlock();
}
}
}
記住:永遠別放棄你當初踏入社會時的夢想,那是你現在最美好的夢想啊!