多線程三種實現方式:同步代碼塊、同步方法、lock鎖

package atguigu.java;

/**
 * 多線程的創建,方式一:繼承於Thread類
 * 1. 創建一個繼承於Thread類的子類
 * 2. 重寫Thread類的run() --> 將此線程執行的操作聲明在run()中
 * 3. 創建Thread類的子類的對象
 * 4. 通過此對象調用start()
 * <p>
 * 例子:遍歷100以內的所有的偶數
 *
 * @author shkstart
 * @create 2019-02-13 上午 11:46
 */

//1. 創建一個繼承於Thread類的子類
class MyThread extends Thread {
    //2. 重寫Thread類的run()
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}


public class ThreadTest {
    public static void main(String[] args) {
        //3. 創建Thread類的子類的對象
        MyThread t1 = new MyThread();

        //4.通過此對象調用start():①啓動當前線程 ② 調用當前線程的run()
        t1.start();
        //問題一:我們不能通過直接調用run()的方式啓動線程。
//        t1.run();

        //問題二:再啓動一個線程,遍歷100以內的偶數。不可以還讓已經start()的線程去執行。會報IllegalThreadStateException
//        t1.start();
        //我們需要重新創建一個線程的對象
        MyThread t2 = new MyThread();
        t2.start();


        //如下操作仍然是在main線程中執行的。
        for (int i = 0; i < 100; i++) {
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" + i + "***********main()************");
            }
        }
    }

}

package atguigu.java;

/**
 * 創建多線程的方式二:實現Runnable接口
 * 1. 創建一個實現了Runnable接口的類
 * 2. 實現類去實現Runnable中的抽象方法:run()
 * 3. 創建實現類的對象
 * 4. 將此對象作爲參數傳遞到Thread類的構造器中,創建Thread類的對象
 * 5. 通過Thread類的對象調用start()
 *
 *
 * 比較創建線程的兩種方式。
 * 開發中:優先選擇:實現Runnable接口的方式
 * 原因:1. 實現的方式沒有類的單繼承性的侷限性
 *      2. 實現的方式更適合來處理多個線程有共享數據的情況。
 *
 * 聯繫:public class Thread implements Runnable
 * 相同點:兩種方式都需要重寫run(),將線程要執行的邏輯聲明在run()中。
 *
 * @author shkstart
 * @create 2019-02-13 下午 4:34
 */
//1. 創建一個實現了Runnable接口的類
class MThread implements Runnable{

    //2. 實現類去實現Runnable中的抽象方法:run()
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }

        }
    }
}


public class ThreadTest1 {
    public static void main(String[] args) {
        //3. 創建實現類的對象
        MThread mThread = new MThread();
        //4. 將此對象作爲參數傳遞到Thread類的構造器中,創建Thread類的對象
        Thread t1 = new Thread(mThread);
        t1.setName("線程1");
        //5. 通過Thread類的對象調用start():① 啓動線程 ②調用當前線程的run()-->調用了Runnable類型的target的run()
        t1.start();

        //再啓動一個線程,遍歷100以內的偶數
        Thread t2 = new Thread(mThread);
        t2.setName("線程2");
        t2.start();
    }

}

package atguigu.java;

/**
 *
 * 例子:創建三個窗口賣票,總票數爲100張.使用繼承Thread類的方式
 *
 * 存在線程的安全問題,待解決。
 *
 * @author shkstart
 * @create 2019-02-13 下午 4:20
 */
class Window extends Thread{


    private static int ticket = 100;
    @Override
    public void run() {

        while(true){

            if(ticket > 0){
                System.out.println(getName() + ":賣票,票號爲:" + ticket);
                ticket--;
            }else{
                break;
            }

        }

    }
}


public class WindowTest {
    public static void main(String[] args) {
        Window t1 = new Window();
        Window t2 = new Window();
        Window t3 = new Window();


        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();

    }
}

package atguigu.java;

/**
 * 例子:創建三個窗口賣票,總票數爲100張.使用實現Runnable接口的方式
 * 存在線程的安全問題,待解決。
 *
 * @author shkstart
 * @create 2019-02-13 下午 4:47
 */
class Window1 implements Runnable{

    private int ticket = 100;

    @Override
    public void run() {
        while(true){
            if(ticket > 0){
                System.out.println(Thread.currentThread().getName() + ":賣票,票號爲:" + ticket);
                ticket--;
            }else{
                break;
            }
        }
    }
}


public class WindowTest1 {
    public static void main(String[] args) {
        Window1 w = new Window1();

        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();
    }

}

package com.atguigu.java1;

import java.util.concurrent.locks.ReentrantLock;

/**
 * 解決線程安全問題的方式三:Lock鎖  --- JDK5.0新增
 *
 * 1. 面試題:synchronized 與 Lock的異同?
 *   相同:二者都可以解決線程安全問題
 *   不同:synchronized機制在執行完相應的同步代碼以後,自動的釋放同步監視器
 *        Lock需要手動的啓動同步(lock()),同時結束同步也需要手動的實現(unlock())
 *
 * 2.優先使用順序:
 * Lock  同步代碼塊(已經進入了方法體,分配了相應資源)  同步方法(在方法體之外)
 *
 *
 *  面試題:如何解決線程安全問題?有幾種方式
 * @author shkstart
 * @create 2019-02-15 下午 3:38
 */
class Window implements Runnable{

    private int ticket = 100;
    //1.實例化ReentrantLock
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while(true){
            try{

                //2.調用鎖定方法lock()
                lock.lock();

                if(ticket > 0){

                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + ":售票,票號爲:" + ticket);
                    ticket--;
                }else{
                    break;
                }
            }finally {
                //3.調用解鎖方法:unlock()
                lock.unlock();
            }

        }
    }
}

public class LockTest {
    public static void main(String[] args) {
        Window w = new Window();

        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();
    }
}

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