線程之菜鳥教程

線程創建

  v1、Runnable實現接口
  v1_1、繼承Thread類
  v1_2、匿名內部類創建線程

線程通信

V2、sleep(100)
    1、Thread類裏的靜態方法
    2、睡眠時間毫秒
    3、不釋放所在線程鎖
v2_1、wait()
    1、java.lang.Object類裏的非靜態方法
    2、wait()調用後,釋放調用wait對象的線程鎖,
       如果對象不佔用鎖則報IllegalMonitorStateException
    3、無參 則會一直等直到 notify()或notifyAll()    
    4、wait(100) 單位毫秒 超時自動被喚醒
v2_2、notify()     
    1、java.lang.Object類裏的非靜態方法
    2、notify()調用後,通知同一個線程鎖下wait(),繼續往下執行
    3、notifyAll()調用後,通知所有線程鎖下wait(),繼續往下執行        
v2_3、join()
    1、Thread類裏的非靜態方法
    2、a.join() 等待a線程執行完畢再接着執行a.join()所在的線程
    3、main{ a.start();b.start();a.join();}
      main線程先開啓了A,B線程,B線程執行不受a.join影響的 
      只是說主線程等待A執行完再執行,B線程是獨立的不受影響的 
 v2_4、Interrupt()
      1、Thread的非靜態方法
      2、thread.interrupt();//設置中斷標誌位爲true
      3、sleep() wait() join() 不斷檢測線程的中斷位 
         如果中斷爲true報InterruptedException 如果false不處理  
      4、拋出InterruptedException 清除中斷標誌位
         即設置中斷標誌位爲false  
 v2_5、yield()
     1、Thread的靜態方法 
     2、線程 從運行狀態--到就緒狀態
     3、線程在 this.start()準備執行——就緒狀態run()運行——就是運行狀態           
 v2_6、對象調用wait()(疑惑-在對象是一個線程的前提下,
       線程開啓再調用調用wait,不會起到等待的效果)

      if(對象==類實例 && 類實例.start()){
            wait()等待的是類實例run方法執行完
      }else {//!類實例.start() || 對象!=類實例
            wait()等待所在線程
      } //TODO 代碼運行總結的不知道對不對 
  v2_7、sleep()和wait()區別  
      1、wait()等待釋放鎖
      2、sleep()等待不釋放鎖

線程關鍵字

v3、volatile
主要總結 volatile修飾 線程私有變量改變主內存立即改變,
        沒有修飾線程私有變量改變等線程結束主內存改變
   內存模型的相關概念
     cup——》   cache
     cup——》   cache|| -----》 總線鎖或者緩存一致性協議----> 主存
     cup——》   cache
   併發編程中的三個概念
     原子性 即一個操作或者多個操作要麼全部執行並且執行的過程不會被任何因素打斷,要麼就都不執行。
     可見性  可見性是指當多個線程訪問同一個變量時,一個線程修改了這個變量的值,其他線程能夠立即看得到修改的值 
     有序性  即程序執行的順序按照代碼的先後順序執行
   volatile具有可見性不具有原子性 
   常用場景:
       1.狀態標記量
       2.double check
v3_1、AtomicInteger  原子性變量
v3_2、ThreadLocal    線程本地變量——每個線程有自己獨立的變量
v3_3、驗證volatile不具備原子性 
     COUNT++不具備原子性COUNT從主內存複製然後+1 
     在執行+1這個操作的時候主內又被複製出去了一份 導致COUNT沒有保證原子性

線程鎖

 v4、synchronized 
    Class類的所有對象的鎖
        鎖類、鎖類的靜態代碼塊、靜態屬性、
    單個對象的鎖
        鎖對像、鎖非靜態代碼塊、鎖非靜態屬性
  v4_1、Lock
     Lock 接口 ReentrantLock實現類
     lock.lock();
     lock.unlock();
     lock如果定義在線程自己的方法類,則只是鎖自己的線程並不能保證多個線程同步執行

線程池

FutureTask
Future是一個接口,代表可以取消的任務,並可以獲得任務的執行結果
FutureTask 是基本的實現了Future和runnable接口
實現runnable接口,說明可以把FutureTask實例傳入到Thread中,在一個新的線程中執行。

=========================================
歡迎指正交流 歡迎指正交流 歡迎指正交流 歡迎指正交流 歡迎指正交流

/**
 * Runnable
 * 實現接口創建線程
 * */
public class V1 implements Runnable {
    @Override
    public void run() {
        System.out.println("hello");
    }

    public static void main(String[] args) {
        Thread  thread = new Thread(new V1());
        thread.start();
    }
}
/**
 * Thread
 * 繼承實現創建線程
 * */
public class V1_1 extends Thread {

    public void run() {
        System.out.println("hello");
    }

    public static void main(String[] args) {
        V1_1 v1_1 = new V1_1();
        v1_1.start();
    }
}
/**
 * Thread
 * 繼承實現創建線程
 * */
public class V1_1 extends Thread {

    public void run() {
        System.out.println("hello");
    }

    public static void main(String[] args) {
        V1_1 v1_1 = new V1_1();
        v1_1.start();
    }
}
/**
 *匿名內部類創建線程
 * */
public class V1_2 {

    public static void main(String[] args) {
        new Thread(new Runnable() {
            public void run() {
                System.out.println("hello");
            }
        }).start();

        //jdk1.8
        new Thread( () -> {System.out.println("hello1");} ).start();
    }
}
/**
 * sleep(100)
 *      1、Thread類裏的靜態方法
 *      2、睡眠時間毫秒
 *      3、不釋放所在線程鎖
 */
public class V2 {
    private static  final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss SSS");

    public static void main(String[] args) {
        System.out.println(df.format(new Date()));
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(df.format(new Date()));
    }
}
/**
 * wait()
 *      1、java.lang.Object類裏的非靜態方法
 *      2、wait()調用後,釋放調用wait對象的線程鎖,如果對象不佔用鎖則報IllegalMonitorStateException
 *      3、無參 則會一直等直到 notify()或notifyAll()
 *      4、wait(100) 單位毫秒 超時自動被喚醒
 */
public class V2_1 {

    public static void main(String[] args) {
      //new V2_1().wait(); 直接調用會報IllegalMonitorStateException

//        V2_1.class 有鎖,但是v2_11沒有鎖所以也會報IllegalMonitorStateException
//        synchronized (V2_1.class){
//            System.out.println(Thread.currentThread().getName());
//            try {
//                V2_1 v2_11 = new V2_1();
//                v2_11.wait();
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }
        V2_1 v2_1 = new V2_1();
        synchronized (v2_1){
            System.out.println(Thread.currentThread().getName());
            try {
                v2_1.wait(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
/**
 * notify()
 *      1、java.lang.Object類裏的非靜態方法
 *      2、notify()調用後,通知同一個線程鎖下wait(),繼續往下執行
 *      3、notifyAll()調用後,通知所有線程鎖下wait(),繼續往下執行
 */
public class V2_2 extends Thread{
    private static  Boolean BOOLEAN = true;

    public void run() {
        synchronized (BOOLEAN){
            if(BOOLEAN){
                try {
                    System.out.println("wait start");
                    BOOLEAN.wait();
                    System.out.println("wait end");
                } catch (InterruptedException e) {

                }
            }else {
                System.out.println("notify start");
                BOOLEAN.notify();
                System.out.println("notify end");
            }
        }
    }


    public static void main(String[] args) throws InterruptedException {
        V2_2 v2_2 = new V2_2();
        V2_2 v2_3 = new V2_2();
        v2_2.start();
        BOOLEAN = false;
        v2_3.start();
    }
}
/**
 * join()
 *  1、Thread類裏的非靜態方法
 *  2、a.join() 等待a線程執行完畢再接着執行a.join()所在的線程
 *  3、main線程先開啓了,A,B線程,B線程執行不受a.join影響的 只是說主線程等待A執行完再執行,B線程是獨立的不受影響的
 */
public class V2_3 {

    public static void main(String[] args) throws InterruptedException {
        Thread a = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("start A");
                try {
                    sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("end A");
            }
        });
        Thread b = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("start B");
                try {
                    sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("end B");
            }
        });
        a.start();
        b.start();
        a.join();
        b.join();
        System.out.println("end");
    }
}
/**
 * Interrupt()
 *      1、Thread的非靜態方法
 *      2、thread.interrupt();//設置中斷標誌位爲true
 *      3、sleep() wait() join() 不斷檢測線程的中斷位 如果中斷爲true報InterruptedException 如果false不處理
 *      4、拋出InterruptedException 清除中斷標誌位即設置中斷標誌位爲false
 *      5、thread.isInterrupted()  獲取中斷標誌位的結果
 */
public class V2_4 extends Thread{
    public static Object lock = new Object();

    @Override
    public void run() {
        System.out.println("start");
        synchronized (lock) {
            try {
                lock.wait();//sleep wait join  不斷檢測線程的中斷位 如果中斷爲true報InterruptedException 如果false不處理
            } catch (InterruptedException e) {//清除中斷標誌位即設置中斷標誌位爲false
                System.out.println(Thread.currentThread().isInterrupted());//獲取中斷標誌位的結果
                Thread.currentThread().interrupt(); //設置中斷標誌位爲true
                System.out.println(Thread.currentThread().isInterrupted());//獲取中斷標誌位的結果
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Thread thread = new V2_4();
        thread.start();
        try {
            sleep(2000);
        } catch (InterruptedException e) {
        }
        thread.interrupt();//設置中斷標誌位爲true
    }
}
/**
 * yield()
 *     Thread的靜態方法
 *     線程 從運行狀態--到就緒狀態
 *     線程在 this.start()準備執行——就緒狀態 ,run()運行——就是運行狀態
 */
public class V2_5 extends Thread{
        @Override
        public void run() {
            for (int i = 1; i <= 50; i++) {
                System.out.println(this.getName() + "  " + i);
                // 當i爲30時,該線程就會把CPU時間讓掉,讓其他或者自己的線程執行(也就是誰先搶到誰執行)
                if (i == 30) {
                    this.yield();
                }
            }
        }

        public static void main(String[] args) {
            V2_5 yt1 = new V2_5();
            V2_5 yt2 = new V2_5();
            yt1.start();
            yt2.start();
        }
}
/**
 * 對象調用wait()
 * if(對象==類實例 && 類實例.start()){
 *     wait()等待的是類實例run方法執行完
 * }else {//!類實例.start() || 對象!=類實例
 *    wait()等待所在線程
 * } TODO 代碼運行總結的不知道對不對
 *
 */
public class V2_6 extends Thread {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + " run ");
        }

        public static void main(String[] args) throws InterruptedException {
            V2_6 V2_6 = new V2_6();
            synchronized(V2_6) {
                try {
                    System.out.println(Thread.currentThread().getName()+" start t1");
                  V2_6.start(); //開啓和註釋驗證
                    System.out.println(Thread.currentThread().getName()+" wait()");
                    V2_6.wait();
                    System.out.println(Thread.currentThread().getName()+" continue");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

}
/**
 * sleep()和wait()區別
 *      1、wait()等待釋放鎖
 *      2、sleep()等待不釋放鎖
 */
public class V2_7 extends Thread{
    private static Object object = new Object();

    @Override
    public void run() {
       waitV2_7(1);
       // sleepV2_7(1);
    }

    private void waitV2_7(Object object){
        synchronized (object){
            System.out.println("wait");
            try {
                object.wait(1000000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void sleepV2_7(Object object){
        synchronized (object){
            try {
                System.out.println("sleep");
                this.sleep(1000000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        V2_7 v2_7 = new V2_7();
        V2_7 v2_8 = new V2_7();
        V2_7 v2_9 = new V2_7();

        v2_7.start();
        v2_8.start();
        v2_9.start();
    }
}
/**
 * volatile
 *  內存模型的相關概念
 *    cup   cache
 *    cup   cache        總線鎖或者緩存一致性協議    主存
 *    cup   cache
 * 併發編程中的三個概念
 *    原子性   即一個操作或者多個操作 要麼全部執行並且執行的過程不會被任何因素打斷,要麼就都不執行。
 *    可見性  可見性是指當多個線程訪問同一個變量時,一個線程修改了這個變量的值,其他線程能夠立即看得到修改的值  V41
 *    有序性  即程序執行的順序按照代碼的先後順序執行
 *  volatile  可見性     原子性 AtomicInteger  Lock  synchronized 保證i++的原子性
 *  常用場景:
 *     1.狀態標記量
 *     2.double check
 *詳見:https://www.cnblogs.com/dolphin0520/p/3920373.html  5volatile使用場景
 *
 *-----------------------------------------------------------------------------------------------------------------------------
 *    //每開啓一個線程  從主內存複製變量到線程的私有工作空間  主線程是 stop = false    A:stop = false    B:stop = false
 *   //沒有volatile修飾  B線程將stop =true因爲B線程還沒有結束所以主內存還是stop = false 當B線程執行完畢更新主內存stop =true 接着A結束
 *   //有volatile修飾  B線程將stop =true 立即將主內存的stop =true 接着A結束,接着B執行
 *
 *   //主內存改變每個子線程就會同步改變  子線程改變如果不是volatile則必須等待子線程完畢纔會改變主內存,如果volatile修飾就會立即改變主內存
 *   //沒有volatile修飾時子線程改變變量主線程爲什麼不會變,  因爲如果有多個子線程都改變則主內存不知道用哪個才正確
 *   沒有volatile修飾stop
 *主要事件                    主               私有線程A             私有線程B
 *
 *stop = false
 *
 *開啓A,B線程             stop = false          拷貝stop = false       拷貝stop = false
 *
 *stop = false           stop = false          stop = true;這時候B還沒有結束
 *
 * stop = true            stop = true            B結束
 *
 *有volatile修飾stop
 *主要事件                    主               私有線程A             私有線程B
 *
 *stop = false
 *
 *開啓A,B線程             stop = false          拷貝stop = false       拷貝stop = false
 *
 *stop = flase           stop = flase          stop = true;這時候B還沒有結束但是隻要改變主內存同步改變
 *
 *stop = true            stop = true
 *主要總結volatile修飾 線程私有變量改變主內存立即改變,沒有修飾線程私有變量改變等線程結束主內存改變
 *
 * 下面例子證明 volatile他有可見性
 */
public class V3  {
//    private static   volatile  boolean stop = false;
      private static   boolean stop = false;

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (!stop){
                    System.out.println("等待主內存改變");
                }
                System.out.println("線程A結束");
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                stop =true;
                try {
                    sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("線程B結束");
            }
        }).start();
    }
}
/**
 * AtomicInteger
 *      原子性變量
 */
public class V3_1 {
    private static  AtomicInteger atomicInteger = new AtomicInteger(0);

    public static void main(String[] args)  {
        for (int i = 0; i < 100; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    atomicInteger.incrementAndGet();
                }
            }).start();
        }
        try {
            sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(atomicInteger);
    }
}
/**
 * ThreadLocal
 *     線程本地變量——每個線程有自己獨立的變量
 */
public class V3_2 {
    private static ThreadLocal threadLocal = new ThreadLocal();
//    private static Integer integer= 0;

    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    threadLocal.set(i);
//                    integer=i;
                    try {
                        sleep(30);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(threadLocal.get()+"_"+Thread.currentThread().getName());
//                    System.out.println(integer+"_"+Thread.currentThread().getName());
                }

            }
        },"thread");

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 200; i < 300; i++) {
                    threadLocal.set(i);
//                    integer=i;
                    try {
                        sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(threadLocal.get()+"_"+Thread.currentThread().getName());
//                    System.out.println(integer+"_"+Thread.currentThread().getName());
                }

            }
        },"thread1");
        thread.start();
        thread1.start();
    }

}
/**
 * 驗證volatile不具備原子性
 * COUNT++不具備原子性 COUNT從主內存複製然後+1 在執行+1這個操作的時候主內又被複製出去了一份 導致COUNT沒有保證原子性
 */
public class V3_3 {
    private static volatile  int COUNT = 0;

    public static void main(String[] args)  {
        for (int i = 0; i < 100; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    COUNT++;
                }
            }).start();
        }
        try {
            sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(COUNT);
    }
}
/**
 * synchronized
 */
public class V4 {
    private static Object o = new Object();
    static V4 lock = new V4();

    // lock on dynamic method
    public synchronized void dynamicMethod() {
        System.out.println("dynamic method");
        sleepSilently(2000);
    }

    // lock on static method
    public static synchronized void staticMethod() {
        System.out.println("static method");
        sleepSilently(2000);
    }

    // lock on this
    public void thisBlock() {
        synchronized (this) {
            System.out.println("this block");
            sleepSilently(2000);
        }
    }

    // lock on an object
    public void objectBlock() {
        synchronized (o) {
            System.out.println("dynamic block");
            sleepSilently(2000);
        }
    }

    // lock on the class
    public static void classBlock() {
        synchronized (V6.class) {
            System.out.println("static block");
            sleepSilently(2000);
        }
    }

    private static void sleepSilently(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {

        // object lock test
        new Thread() {
            @Override
            public void run() {
                lock.dynamicMethod();
            }
        }.start();
        new Thread() {
            @Override
            public void run() {
                lock.thisBlock();
            }
        }.start();
        new Thread() {
            @Override
            public void run() {
                lock.objectBlock();
            }
        }.start();

        sleepSilently(3000);
        System.out.println();

        // class lock test
        new Thread() {
            @Override
            public void run() {
                lock.staticMethod();
            }
        }.start();
        new Thread() {
            @Override
            public void run() {
                lock.classBlock();
            }
        }.start();

    }
}
/**
 * Lock
 *    Lock 接口 ReentrantLock實現類
 *    lock.lock();
 *    lock.unlock();
 *    lock如果定義在線程自己的方法類,則只是鎖自己的線程並不能保證多個線程同步執行
 */
public class V4_1 {
    private ArrayList<Integer> arrayList = new ArrayList<Integer>();
    private Lock lock = new ReentrantLock();    //注意這個地方
    public static void main(String[] args)  {
        final V4_1 test = new V4_1();
        for (int i = 0; i < 3; i++) {
            new Thread(){
                public void run() {
                    test.insert(Thread.currentThread());
                };
            }.start();
        }
    }

    public void insert(Thread thread) {
//      Lock lock = new ReentrantLock();    //加在這裏不保證外面開啓多線程同步
        lock.lock();
        try {
            System.out.println(thread.getName()+"得到了鎖");
            for(int i=0;i<5;i++) {
                arrayList.add(i);
            }
        } catch (Exception e) {
        }finally {
            System.out.println(thread.getName()+"釋放了鎖");
            lock.unlock();
        }
    }
}
/**
 * FutureTask
 *
 Future是一個接口,代表可以取消的任務,並可以獲得任務的執行結果

 FutureTask 是基本的實現了Future和runnable接口
 實現runnable接口,說明可以把FutureTask實例傳入到Thread中,在一個新的線程中執行。
 實現Future接口,說明可以從FutureTask中通過get取到任務的返回結果,也可以取消任務執行(通過interreput中斷)
 * //從1+10000000000
 */
public class V5 {
    private static final Long  LENGTH = 1000000000L;
    private static final Long  AREA = 10000000L;

    public static void main(String[] args) {

        V5 inst=new V5();
        // 創建任務集合
        List<FutureTask<Long>> taskList = new ArrayList<FutureTask<Long>>();
        // 創建線程池
        ExecutorService exec = Executors.newFixedThreadPool(5);
        for (long i = 0; i < LENGTH/AREA; i++) {
            // 傳入Callable對象創建FutureTask對象
            FutureTask<Long> ft = new FutureTask<Long>(inst.new ComputeTask(i*AREA,(i+1)*AREA));
            taskList.add(ft);
            // 提交給線程池執行任務,也可以通過exec.invokeAll(taskList)一次性提交所有任務;
            exec.submit(ft);
        }

        System.out.println("所有計算任務提交完畢, 主線程接着幹其他事情!");

        // 開始統計各計算線程計算結果
        Long totalResult = 0L;
        for (FutureTask<Long> ft : taskList) {
            try {
                //FutureTask的get方法會自動阻塞,直到獲取計算結果爲止
                totalResult = totalResult + ft.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }

        // 關閉線程池
        exec.shutdown();
        System.out.println("多任務計算後的總結果是:" + totalResult);

    }

    private class ComputeTask implements Callable<Long> {
        private Long start;
        private Long end;

        public ComputeTask(Long start, Long end){
            this.start = start;
            this.end = end;
        }

        @Override
        public Long call() throws Exception {
            Long result =0L;
           for (Long i =  start; i<end;i++){
               result = result+i;
           }
            return result;
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章