1. 程式人生 > >執行緒、執行緒匿名內部類、解決執行緒不安全的方式

執行緒、執行緒匿名內部類、解決執行緒不安全的方式

執行緒

執行緒:正在執行的程式,是程式的執行路徑;多線性

程序:是應用程式的載體,程式執行在虛擬機器中。一個應用軟體對應一個程序。

一個程序包含多個執行緒,一個執行緒對應一個程序。

好處:提高軟體的執行效率

多執行緒的執行原理

在同一時刻只能有一個執行緒正在使用CPU,作業系統設計了CPU的排程方式。

  • 分時呼叫:平均分配使用CPU的使用時間
  • 搶佔式排程:根據執行緒的優先順序分配CPU資源

開發多執行緒的方式

  • 繼承Thread類
  • 實現Runnable介面

Thread類

構造方法:

成員方法:
- int getPriority() 返回執行緒的優先順序。
- String getName() 返回該執行緒的名稱。
- void run()執行執行緒邏輯的程式碼
- void start()開啟執行緒,使執行緒處於就緒狀態,等待CPU的排程。

執行緒使用

定義子執行緒類(繼承Thread或者實現Runable介面),重寫run()方法。

建立執行緒物件,呼叫start()方法。

子執行緒

public class DemoThread extends Thread {
    public DemoThread(){}
    public DemoThread(String name){
        super(name);
    }
    @Override
    public void run() {
        Thread demo = Thread.currentThread();
        String demoName = demo.getName();
        System.out.println(demoName);
    }


}

主執行緒

public class DemoMain {

    public static void main(String[] args) {
        Thread main = Thread.currentThread();
        String mainName = main.getName();
        System.out.println(mainName);
        //建立子執行緒的物件
        DemoThread dt=new DemoThread("我是子執行緒");
        dt.start();
        System.out.println("主執行緒");
    }
}

實現Runnable介面

  1. 定義類實現Runnable介面,重寫run()方法(執行緒執行的程式碼)
  2. 建立子執行緒任務物件
  3. 建立子執行緒物件
  4. 呼叫start()方法。

子執行緒

public class DemoRunable implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());

    }

}

主執行緒

public class MainRunnable {

    public static void main(String[] args) {
        //建立子任務
        DemoRunable dr=new DemoRunable();
        //建立子執行緒物件
        Thread td=new Thread(dr,"子執行緒");
        td.start();
    }
}

兩種方式的區別

  1. 繼承Thread類, 任務與子執行緒程式碼 耦合(關聯性)到一起。
  2. 實現Runnable介面,把任務程式碼和子執行緒的程式碼分開(解耦性強)
  3. 繼承擴充套件性差、不能繼承其他的父類,只能繼承一個父類。

執行緒匿名內部類使用

/**
 *只調用一次執行緒
 * @author YandeHu
 *
 */
public class DemoInner {

    public static void main(String[] args) {
        new Thread(){
            @Override
            public void run() {
            System.out.println(Thread.currentThread().getName());
            System.out.println("Thread繼承子執行緒匿名內部類的程式碼");
            }
        }.start();

        Runnable r=new Runnable(){
            @Override
            public void run() {
                System.out.println("Runnable1 匿名自內部物件");
            }
        };
        Thread td=new Thread(r);
        td.start();
        new Thread(new Runnable(){
            @Override
            public void run() {
                System.out.println("Runnable2 匿名自內部物件");
            }
        }).start();
    }
}

解決執行緒不安全的方式

保證修改共享資料的程式碼在同一時刻只能一個執行緒訪問,保證執行緒是同步的。

  1. 使用同步程式碼塊

    1. 使用關鍵字 syncronized 修改共享程式碼塊
    2. 同步:程式碼一行一行的往下執行
    3. 非同步:多個執行緒同時執行
    4. 鎖物件:任意的物件型別 ,只有執行緒拿到此物件,才能執行程式碼。

    public class TiketRunnable implements Runnable {

    int tiketNumber=100;
    //鎖物件 只有獲得鎖物件的執行緒才可以執行
    Object obj=new Object();
    @Override
    public void run() {
        while(true){
            synchronized (obj) {
                if(tiketNumber>0){
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    System.out.println("執行緒"+Thread.currentThread().getName()+" 正在賣"+(tiketNumber--)+"張票");
                }
    
            }
        }
        }
     }
    

Lock介面

Lock lock=new ReentrantLock();

//重寫run方法
public void run() {

lock.lock();
 同步程式碼

lock.unlock();

}
Lock lock=new ReentrantLock();
@Override
public void run() {
    while(true){
        lock.lock();

        if(tiketNumber>0){
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("執行緒"+Thread.currentThread().getName()+" 正在賣"+(tiketNumber--)+"張票");
        }
        lock.unlock();
    }