【多線程與高併發】--相關知識梳理---提升自己值得擁有

前言

本篇博客主要總結了,多線程與高併發相關知識,目的是提升自己技術能力同時也能幫助你。


1.線程中的run與start的區別

package com.zcw.demo.demo1;

import java.util.concurrent.TimeUnit;

/**
 * @ClassName : ZCWThread
 * @Description :線程中start 方法與run方法
 * @Author : Zhaocunwei
 * @Date: 2020-06-13 13:39
 */
public class ZCWThread {
    private static class T1 extends  Thread{
        @Override
        public void run(){
            for(int i=0;i<10;i++){
                try {
                    TimeUnit.MICROSECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("T1");
            }
        }
    }

    public static void main(String[] args) {
        new T1().start();
//        new T1().run();
        for(int i=0;i<10;i++){
            try {
                TimeUnit.MICROSECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("main");
        }
    }
}



運行結果:

在這裏插入圖片描述
在這裏插入圖片描述
通過上面兩個圖分析原因,當我們調用start方法時,會在調用start方法那裏產生分支,這個分支和我的主程序一起執行,run方法呢,就一個執行路徑。

2.創建線程的兩種方式-啓動線程程序的三種方式

package com.zcw.demo.demo1;

/**
 * @ClassName : HowToCreateThread
 * @Description :創建線程的兩種方式
 * @Author : Zhaocunwei
 * @Date: 2020-06-13 14:15
 */
public class HowToCreateThread {
    static class MyThread extends Thread{
        @Override
        public void run (){
            System.out.println("Hello MyThread!");
        }
        static class MyRun implements  Runnable{
            @Override
            public void run(){
                System.out.println("Hello MyRun!");
            }

            public static void main(String[] args) {
                new MyThread().start();
                new Thread(new MyRun()).start();
                new Thread(() ->{
                    System.out.println("Hello lambda!");
                }).start();
            }
        }
    }
}



啓動線程的三種方式:
1.Thread
2.Runnable
3.Executors.newCachedThrad

3.線程中的基本方法

package com.zcw.demo.demo1;

/**
 * @ClassName : Sleep_yield_Join
 * @Description :線程中的基本方法
 * @Author : Zhaocunwei
 * @Date: 2020-06-13 14:24
 */
public class Sleep_yield_Join {
    public static void main(String[] args){
        //testSleep();
        //testYield();
        //testJoin();
    }
    static void testSleep(){
        new Thread(()->{
            for(int i=0;i<100;i++){
                System.out.println("A"+i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
    static void testYield(){
        new Thread(()->{
            for(int i=0;i<100;i++){
                System.out.println("A"+i);
            }
        }).start();
        new Thread(()->{
            for(int i=0;i<100;i++){
                System.out.println("------------------------B"+i);
                if(i%10 == 0){
                    Thread.yield();
                }
            }
        }).start();
    }
    static void testJoin(){
        Thread t1= new Thread(()->{
            for(int i=0;i<100;i++){
                System.out.println("A"+i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread t2 = new Thread(() ->{
            try {
                t1.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            for(int i=0; i<100; i++){
                System.out.println("A"+i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();
        t2.start();
    }
}



  • 線程狀態

package com.zcw.demo.demo1;

/**
 * @ClassName : ThreadState
 * @Description :
 * @Author : Zhaocunwei
 * @Date: 2020-06-13 14:54
 */
public class ThreadState {
    static class MyThread extends Thread{
        @Override
        public void run(){
            System.out.println(this.getState());
            for (int i=0;i<10;i++){
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(i);
            }
        }
    }

    public static void main(String[] args) {
        Thread t = new MyThread();
        System.out.println(t.getState());
        t.start();
         try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(t.getState());
    }
}


4.Synchronized關鍵字對某個對象加鎖

package com.zcw.demo.demo1;

/**
 * @ClassName : MySynchronized
 * @Description : Synchronized關鍵字對某個對象加鎖
 * @Author : Zhaocunwei
 * @Date: 2020-06-13 15:20
 */
public class MySynchronized {
    private static int count=10;
    private Object o = new Object();

    public void m(){
        //任何線程要執行下面的代碼,必須先拿到0的項
        synchronized (o){
            count --;
            System.out.println(Thread.currentThread().getName()+" count="+count);
        }
    }
    //考慮一下這裏? synchronized(this)是否可以?
    public static void  mm(){
        synchronized (MySynchronized.class){
            count --;
        }
    }
}



  • synchronized(Object)不能用String,常量,Integer long
  • 線程同步
    synchronized
    1.鎖的是對象不是代碼
    2.this xxx.class
    3鎖定方法,非鎖定方法同時執行。
    4.鎖升級: 偏向鎖,自旋鎖,重量級鎖,線程數少,自旋鎖多。
    操作消耗時間長,重量級鎖

5.Volatile

  • 保證線程可見性
  • 禁止指令重排序
    – DCL單例
    –Double Check Lock
    –Mgr06.java
package com.zcw.demo.demo2;

import java.util.concurrent.TimeUnit;

/**
 * @ClassName : T
 * @Description :
 * @Author : Zhaocunwei
 * @Date: 2020-06-15 12:22
 */
public class T {
    /**volatile**/ boolean running =true;//對比一下在volatile的情況下,整個程序運行結果的區別
    void m(){
        System.out.println("m start");
        while(running){
            try {
                TimeUnit.MILLISECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
        System.out.println("m end");
    }

    public static void main(String[] args) {
        T t = new T();
        new Thread(t::m,"t1").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t.running=false;
    }
}


  • 運行結果:
m start
m end

  • 單例
    餓漢式:
    類加載到內存中後,就實例化一個單例,JVM保證線程安全,簡單實用,推薦使用,但是它的缺點是,不管用與否,類裝載時就實例化,Class.forName("")
package com.zcw.demo.demo2;

/**
 * @ClassName : Mgro1
 * @Description :餓漢式
 * @Author : Zhaocunwei
 * @Date: 2020-06-15 12:44
 */
public class Mgro1 {
    private static final Mgro1 INSTANCE = new Mgro1();
    private Mgro1(){};
    public static Mgro1 getInstance(){
        return INSTANCE;
    }
    public void m(){
        System.out.println("m");
    }

    public static void main(String[] args) {
        Mgro1 m1 = Mgro1.getInstance();
        Mgro1 m2 =Mgro1.getInstance();
        System.out.println(m1==m2);
    }
}



  • 運行結果:

true

  • 懶漢式
    1.線程不安全的

package com.zcw.demo.demo2;

/**
 * @ClassName : Mgr03
 * @Description :
 * @Author : Zhaocunwei
 * @Date: 2020-06-15 12:50
 */
public class Mgr03 {
    private static Mgr03 INSTANCE;
    private Mgr03(){

    }
    public static Mgr03 getInstance(){
        if(INSTANCE == null){
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            INSTANCE= new Mgr03();
        }
        return INSTANCE;
    }
    public void m(){
        System.out.println("m");
    }

    public static void main(String[] args) {
        for(int i=0; i<10;i++){
            new Thread(()->
            System.out.println(Mgr03.getInstance().hashCode())
            ).start();
        }
    }
}


  • 運行結果:
1899625310
524631667
860147208
653846628
101695638
315181923
810466593
319155376
1035305589
1035305589


把上面的類創建爲線程安全的:

package com.zcw.demo.demo2;

/**
 * @ClassName : Mgr04
 * @Description : lazy loading
 *                 也稱爲懶漢式
 *                 雖然達到了按需初始化的目的,但是帶來了線程不安全的問題,
 *                 可以通過synchronized解決,但也帶來效率下降
 * @Author : Zhaocunwei
 * @Date: 2020-06-15 12:55
 */
public class Mgr04 {
    private static Mgr04 INSTANCE;
    private Mgr04(){

    }
    public static synchronized  Mgr04 getInstance(){
        if(INSTANCE == null){
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            INSTANCE = new Mgr04();
        }
        return  INSTANCE;
    }
    public void m(){
        System.out.println("m");
    }

    public static void main(String[] args) {
        for(int i =0;i<10;i++){
            new Thread(()->{
                System.out.println(Mgr04.getInstance().hashCode());
            }).start();
        }
    }
}


  • 運行結果:
554241184
554241184
554241184
554241184
554241184
554241184
554241184
554241184
554241184
554241184

  • 單例模式添加volatile解決指令重排序問題

package com.zcw.demo.demo2;

/**
 * @ClassName : Mgr06
 * @Description :
 * @Author : Zhaocunwei
 * @Date: 2020-06-15 13:11
 */
public class Mgr06 {
    private static volatile Mgr06 INSTANCE;
    private Mgr06(){

    }
    public static Mgr06 getInstance(){
        if(INSTANCE ==null){
            synchronized (Mgr06.class){
                if(INSTANCE ==null){
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    INSTANCE = new Mgr06();
                }
            }
        }
        return INSTANCE;
    }
    public void m(){
        System.out.println("m");
    }

    public static void main(String[] args) {
        for(int i=0;i<100;i++){
            new Thread(()->{
                System.out.println(Mgr06.getInstance().hashCode());
            }).start();
        }
    }
}


  • 運行結果:
315181923
315181923
315181923
315181923
315181923
315181923
 ... ...

5.CAS(無鎖優化 自旋)

  • Compare And Swap
  • 原子性
package com.zcw.demo.demo2;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @ClassName : AtomicInteger
 * @Description :
 * @Author : Zhaocunwei
 * @Date: 2020-06-15 13:48
 */
public class MyAtomicInteger {
    AtomicInteger count = new AtomicInteger(0);
    void m(){
        for(int i=0;i<1000;i++){
            count.incrementAndGet();
        }
    }

    public static void main(String[] args) {
        MyAtomicInteger t = new MyAtomicInteger();
        List<Thread> threads = new ArrayList<>();
        for(int i=0;i<10;i++){
            threads.add(new Thread(t::m,"thread-"+i));
        }
        threads.forEach((o)->o.start());
        threads.forEach((o)->{
            try {
                o.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        System.out.println(t.count);
    }

}


  • 運行結果:
10000

出現ABA問題

– 加version,或者添加標籤解決問題
weakCompareAndSetObject


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