方式一:實現Runnable接口
1,自定義多線程類,並實現Runnable接口
2,添加父接口中未實現的run()方法,run()方法里面放着的是我們的業務代碼
3,創建自定義對象,只創建一次,作為業務對象存在
4,創建對個Thread線程類對象,並且將業務對象交給線程對象來完成
5,以多線程的方式啟動多個線程對象
優點:自定義線程只是實現了Runnable接口,后續還可以繼承其他類,多線程可以共享同一個target對象,非常適合多個相同線程來處理同一份資源的情況(比如:多個窗口售票的場景)
缺點:編程復制,如果想訪問當前線程則需要使用Thread.currentThread()靜態對象的getName() 方法來獲取當前線程
代碼如下:
package cn.tedu.thread;
public class TestRunnableV2 {
public static void main(String[] args) {
TicketsRunnableV2 target=new TicketsRunnableV2();
Thread t1=new Thread(target);
Thread t2=new Thread(target);
Thread t3=new Thread(target);
Thread t4=new Thread(target);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
/*
同步鎖:
相當於給容易出現問題的代碼加了一把鎖,包裹了所有可能會出現數據安全問題的代碼加鎖之后,
就有了同步(排隊)的效果,但是加鎖的范圍需要考慮
不能太大:太大效率低下
不能太小:出現數據安全問題
*/
class TicketsRunnableV2 implements Runnable{
int tickets=100;
@Override
public void run() {
while (true){
/*
同步代碼塊:synchronizde(鎖對象){會出現安全隱患的所有代碼}
在同步代碼塊中的代碼,同一時刻只會被一個線程執行
注意:同步代碼塊必須保證所有線程對象使用同一一把唯一的鎖
*/
synchronized (TicketsRunnableV2.class) {//同步鎖的唯一性,解決重賣的情況
if(tickets>0){//解決多賣的情況
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "==" + tickets--);
}
if (tickets <= 0) break;
}
}
}
}
方式一:繼承Thread類
1,繼承Thread類,自定義類並且繼承Thread類
2,在自定義類中重寫Thread類的run()方法,這run()方法存放的是我們自己的業務代碼
3,創建自定義線程對象(該步驟對應線程狀態的新建狀態)
4,調用start()方法以多線程的方式將多個線程對象加入到線程就緒隊列中,等待OS選中
優點:編寫簡單
缺點:繼承的耦合度較高,自定義的線程類繼承了