併發編程(基礎篇)

進程與線程

進程:系統資源調度與分配的基本單位,一個進程至少有一個線程,進程裏面的線程共享進程資源(網絡、磁盤空間、內存)

線程:cpu分配的基本單位(CPU資源共享)

線程共享區和線程獨享區

 

線程的生命週期

新建狀態(new):當線程對象創建後,即新建狀態;

就緒狀態(Runnable):當線程調用start()方法時,線程進入就緒狀態,等待CPU時間片的分配;

運行狀態(Running):當就緒狀態的線程獲取到CPU分配的時間片時,此刻線程進入運行狀態;

阻塞狀態(Blocked):處於運行狀態中的線程由於某種原因,暫時放棄對CPU的使用權,停止執行,此時進入阻塞狀態,

                                     直到其進入到就緒狀態,纔有機會再次被CPU調用以進入到運行狀態;

阻塞的分類

① 同步阻塞:當前線程執行時候需要去獲取鎖的時候(鎖可能被其他線程佔用未被釋放),此刻當前線程會

                        進入阻塞狀態   (synchronized);

② 等待阻塞:當前線程調用wait()方法時,會進入等待阻塞狀態,直到當前線程被通知纔會繼續執行,一般和

                        notify()和notifyAll()方法聯合使用;

③ 其他阻塞:當前線程調用join()會sleep()會進入阻塞狀態,當sleep()狀態超時、join()等待線程終止或者超時、

                       或者I/O處理完畢時,線程重新轉入就緒狀態;

死亡狀態(Dead):當前線程執行完成或者異常退出,那麼當前線程生命週期結束。

線程創建的幾種方式

方式1:通過繼承Thread創建線程,重寫run()方法實現業務

public class ThreadDemo extends Thread {

    @Override
    public void run() {
        System.out.println("嗨!我是通過繼承Thread類創建的線程"+this.getName()+",麼麼噠!!!");
    }

    public static void main(String[] args) {
        //方式1運行
        ThreadDemo threadDemo = new ThreadDemo();
        Thread thread = new Thread(threadDemo);
        thread.start();
        //方式2運行
        new ThreadDemo().start();
    }
}

嗨!我是通過繼承Thread類創建的線程Thread-2,麼麼噠!!!
嗨!我是通過繼承Thread類創建的線程Thread-0,麼麼噠!!!

方式2:實現Runnable接口創建線程類,重寫run()實現業務

public class ThreadDemo1 implements Runnable {

    private  static volatile int money = 1;

    /**
     * @see Thread#run()
     */
    @Override
    public void run() {
        System.out.println("嗨,我是通過實現Runnable接口創建的線程"+Thread.currentThread().getName()+"!!!麼麼噠");
    }


    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new ThreadDemo1());
        thread.start();

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread1 修改成員屬性---> " + ++money);
            }
        });
        thread1.start();

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread2 修改成員屬性---> " + ++money);
            }
        });
        thread2.start();
    }
}

嗨,我是通過實現Runnable接口創建的線程Thread-0!!!麼麼噠
thread1 修改成員屬性---> 2
thread2 修改成員屬性---> 3

方式3:通過實現Callable接口創建線程,重寫call()方法實現業務

@Data
@ToString
public class User {

    private String name;

    private int age;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

  }

public class ThreadDemo2 implements Callable<User> {

    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    @Override
    public User call() throws Exception {
        System.out.println("嗨!我是實現Callable<T> 接口創建的線程"+Thread.currentThread().getName()+",我有返回值哦,麼麼噠!!!");
        return new User("麼麼噠", 1);
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ThreadDemo2 threadDemo2 = new ThreadDemo2();
        FutureTask<User> futureTask = new FutureTask<User>(threadDemo2);
        new Thread(futureTask).start();
        User user = futureTask.get();
        System.out.println(user);
    }
}

嗨!我是實現Callable<T> 接口創建的線程Thread-0,我有返回值哦,麼麼噠!!!
User(name=麼麼噠, age=1)

方式4:使用線程池例如用Executor框架,後續再詳解

幾種方式創建線程優缺點比較

通過繼承Thread:

      優點:編寫簡單,如果需要訪問當前線程,則無須使用Thread.currentThread()方法,直接使用this即可獲得當前線程;

      缺點:繼承了Thread不能再繼承其他類,擴展性不好,不適應於多線程;

通過實現Runnable接口:

      優點:可以繼承其他類、擴展性好;通過上面thread1、thread2操作money可以看出,實現接口可以多線程target的共享,適用於多線程;

      缺點:編程稍稍複雜,不能使用Thread的方法,如果需要訪問當前線程,則必須使用Thread.currentThread()方法;

通過實現Callable接口:

      優點:可以繼承其他類、擴展性好;多個線程可以共享同一個target對象,所以非常適合多個相同線程來處理同一份資源的情況,非常適合創建多線程;和Runnable不同的是,該方式有返回值,可以做一些業務處理;

      缺點:編程稍稍複雜,不能使用Thread的方法,如果需要訪問當前線程,則必須使用Thread.currentThread()方法;

總結:Thread編程簡單,不適用多線程環境;Runnable、Callable編程稍微複雜點,但是非常適合多線程環境;

            Callable有返回值;

線程常用方法介紹

    

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章