java中關於執行緒Thread的建立和同步總結
阿新 • • 發佈:2021-01-27
技術標籤:java
一、程序與執行緒的概念
程序是記憶體中執行的一個應用程式,執行緒是程序中的一個執行單元。
一個程式可以有多個程序,一個程序可以有多個執行緒且至少有一個執行緒。
二、Java中建立執行緒的兩種方式
- 定義Thread的子類,並重寫該類的run方法
public class MyThread extends Thread{
@Override
public void run() {
for (int i=0;i<20;i++){
System.out.println("齊天大聖:"+i);
}
}
}
public class HelloThread {
public static void main(String[] args) {
// 建立子類例項,即建立了執行緒物件
MyThread myThread = new MyThread();
myThread.start();// 呼叫start()方法啟動該執行緒
}
}
- 定義Runnable介面的實現類,並重寫該介面run()方法
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i=0;i<10;i++){
// 輸出內容:執行緒名稱:i
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public class HelloThread {
public static void main(String[] args) {
// 建立該介面實現類的例項
MyRunnable mr = new MyRunnable ();
// 以此例項mr 作為Thread的target來建立Thread類的物件,
// 注意!該物件tr才是真正的執行緒物件(其實這種建立方式也就實現了同一執行緒的資源共享!)
Thread tr= new Thread(mr,"執行緒1");
tr.start();
}
}
三、兩種建立執行緒的方式Thread和Runnable的區別
若一個類繼承Thread,則不適合資源共享。若實現了Runnable,則很容易資源共享。(資源共享簡單舉例就是多個視窗賣100張票那個例子)
總結: 實現Runnable介面比繼承Thread類所具有的優勢:
- 適合多個相同的程式程式碼的執行緒去共享同一個資源。
- 可以避免java中的單繼承的侷限性。
- 增加程式的健壯性,實現解耦操作,程式碼可以被多個執行緒共享,程式碼和執行緒獨立。
- 執行緒池只能放入實現Runable或Callable類執行緒,不能直接放入繼承Thread的類。
(其實,不管是繼承Thread類還是實現Runnable介面來建立執行緒,最終都是通過Thread的物件API來控制執行緒的。)
四、執行緒安全
這裡舉最簡單的賣票案例來說明
首先定義一個實現Runnable介面的類Ticket
public class Ticket implements Runnable{
private int tickets=100;
@Override
public void run() {
while (true){
if (tickets>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 正在賣第:"+tickets--+"張票");
}
}
}
}
建立測試類,開始賣票
public class TestDemo {
public static void main(String[] args) {
// 建立執行緒任務物件
Ticket ticket = new Ticket();
// 建立3個視窗物件(Runnable的好處在此就體現出來了,3個執行緒可以同時共享這100張票,實現了資源共享)
Thread t1 = new Thread(ticket,"視窗1");
Thread t2 = new Thread(ticket,"視窗2");
Thread t3 = new Thread(ticket,"視窗3");
// 3個視窗開始賣票
t1.start();
t2.start();
t3.start();
}
}
輸入結果:
此時出現了執行緒安全的問題,5出現2次,且票數出現了0和-1
這是因為當執行緒1在執行時,還沒執行完,執行緒2或者3也執行開始,導致票數在不同的執行緒裡出現了重複或者不存在。
解決方案:
- 利用java中提供的同步機制synchronized關鍵字來解決
public class Ticket implements Runnable{
private int tickets=100;
private Object lock = new Object();
@Override
public void run() {
while (true){
synchronized (lock){ // lock 是一個鎖物件,該物件可以是任意型別,但是多個物件要使用同一把鎖才能起到效果
if (tickets>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 正在賣第:"+tickets--+"張票");
}
}
}
}
}
2.Lock鎖:java.util.concurrent.locks.Lock 機制提供了比synchronized程式碼塊和synchronized方法更廣泛的鎖定操作, 同步程式碼塊/同步方法具有的功能Lock都有,除此之外更強大,更體現面向物件。
public class Ticket implements Runnable{
private int tickets=100;
Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
lock.lock(); // 加同步鎖
if (tickets>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 正在賣第:"+tickets--+"張票");
}
lock.unlock(); // 釋放同步鎖
}
}
}