juc基礎

回顧多線程

線程的六個狀態

 //獲取CPU的核數
        System.out.println(
                Runtime.getRuntime()
                .availableProcessors()
        );
//Thread 的六種狀態,枚舉
        Thread.State.values()        
public enum State {
        
        NEW,
 
        RUNNABLE,

         
        BLOCKED,

        
        WAITING,

        
        TIMED_WAITING,
 
        TERMINATED;
    }

操作系統層面是 5個, java 定義了 6個

wait 和 sleep區別

1.鎖的釋放

  1. wait釋放鎖,sleep抱着鎖睡覺,不釋放

2.使用範圍不同

  1. wait必須在同步代碼塊中
  2. sleep可以在任意一個地方睡
  3. 是否需要捕獲異常(wait不用捕獲異常,sleep必須捕獲異常)

3. lock

在這裏插入圖片描述

3. Synchronized 和 lock的區別

  1. synchronized 是內置的java關鍵字, Lock是一個java類
  2. Synchronized 無法判斷獲取鎖的狀態,Lock 可以判斷是否獲取到了鎖
  3. Synchronized 全自動釋放鎖
  4. lock必須手動釋放鎖,不然就是死鎖
  5. lock鎖有一個 tryLock的方法,可以嘗試獲取鎖(可以判斷鎖的狀態),不一定像Synchronized鎖一樣,一直阻塞下去
  6. Synchronized 可重入鎖,不可以中斷,非公平; lock,可重入,不可以中斷,非公平(也可以改成公平鎖),相比之下,lock比較靈活

線程中的協作問題!!(生產者和消費者的協作)

package example;



/**
 * @Author lyr
 * @create 2020/5/29 19:01
 */
public class Main {
    public static void main(String[] args) throws ClassNotFoundException {
        Resource s = new Resource();
        new Thread(()->{
            for(int i=0;i<10;++i) {
                s.incr();
            }
        },"A線程").start();
        new Thread(()->{
            for(int j=0;j<10;++j) {
                s.decr();
            }
        },"B線程").start();
    }

    static class Resource {
        private int number;
        // private Object monitor;
        public synchronized void incr()   {
            while (number>0) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            this.number++;
            System.out.println("A線程 "+number);
            this.notifyAll();
        }
        public synchronized void decr()   {
            while (number<=0) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            this.number--;
            System.out.println("B線程 "+number);
            this.notifyAll();
        }
    }
}


4.線程的協作

在這裏插入圖片描述

使用Condition 的優勢!

Condition 可以代替 signal 隨機分佈,也可以是的線程有序執行,即 你可以使用 condition 精準的通知線程

有序執行。

package example;


import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author lyr
 * @create 2020/5/29 19:01
 */
public class Main {
    public static void main(String[] args) throws ClassNotFoundException {
        Resource s = new Resource();
        new Thread(()->{
            for(int i=0;i<10;++i) {
                s.printA();
            }
        },"A線程").start();
        new Thread(()->{
            for(int j=0;j<10;++j) {
                s.printB();
            }
        },"B線程").start();
        new Thread(()->{
            for(int j=0;j<10;++j) {
                s.printC();
            }
        },"C線程").start();
    }

    static class Resource {
        private int number = 1;
        private Lock lock = new ReentrantLock();
        private Condition conditionA = lock.newCondition();
        private Condition conditionB = lock.newCondition();
        private Condition conditionC = lock.newCondition();

        public  void printA()   {
            lock.lock();
            try{
                while (number!=1) {
                    conditionA.await();
                }
                System.out.println(
                        Thread.currentThread().getName()
                );
                number = 2;
                conditionB.signal();
            }catch (Exception ex) {
                System.out.println(ex);
            }finally {
                lock.unlock();
            }
        }
        public void printB() {
            lock.lock();
            try{
                while (number!=2) {
                    conditionB.await();
                }
                System.out.println(
                        Thread.currentThread().getName()
                );
                number = 3;
                conditionC.signal();
            }catch (Exception ex) {
                System.out.println(ex);
            }finally {
                lock.unlock();
            }
        }

        public void printC() {
            lock.lock();
            try{
                while (number!=3) {
                    conditionC.await();
                }
                System.out.println(
                        Thread.currentThread().getName()
                );
                number = 1;
                conditionA.signal();
            }catch (Exception ex) {
                System.out.println(ex);
            }finally {
                lock.unlock();
            }
        }

    }
}

copyOnWriteArrayList

copyOnwrite 採用寫入時複製,讀寫分離的方式。
只在寫操作的時候加鎖。

public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }
    
    
    final void setArray(Object[] a) {
        array = a;
    }

我們先試試在多線程中打印 操作 ArrayList

併發修改異常

package example;


import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * @Author lyr
 * @create 2020/5/29 19:01
 */
public class Main {
    public static void main(String[] args) throws ClassNotFoundException {
        List list = new ArrayList<>();

        for(int i=1;i<10;++i) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString());
                System.out.println(list);
            }).start();
        }

    }


}

null, d43b5115-f131-4a9a-8c17-685d1463c298, e3a0ddf5-1906-4b86-9367-6b2c46313139, 42143054-8fb2-4810-a6b2-73ee99325b04, f9579c0e-144b-4b28-8ee4-b0d92fb1c63d, 48d97a2c-59e1-4b96-823e-ed41aae01703, 9bfdddc9-e3df-4757-bfc0-cc62408f57d5]
[null, d43b5115-f131-4a9a-8c17-685d1463c298, e3a0ddf5-1906-4b86-9367-6b2c46313139, 42143054-8fb2-4810-a6b2-73ee99325b04, f9579c0e-144b-4b28-8ee4-b0d92fb1c63d, 48d97a2c-59e1-4b96-823e-ed41aae01703]
Exception in thread “Thread-4” Exception in thread “Thread-0” Exception in thread “Thread-3” Exception in thread “Thread-6” java.util.ConcurrentModificationException
at java.util.ArrayListItr.checkForComodification(ArrayList.java:909)atjava.util.ArrayListItr.checkForComodification(ArrayList.java:909) at java.util.ArrayListItr.next(ArrayList.java:859)
at java.util.AbstractCollection.toString(AbstractCollection.java:461)
at java.lang.String.valueOf(String.java:2994)
at java.io.PrintStream.println(PrintStream.java:821)
at example.Main.lambda$main0(Main.java:19)atjava.lang.Thread.run(Thread.java:748)java.util.ConcurrentModificationExceptionatjava.util.ArrayList0(Main.java:19) at java.lang.Thread.run(Thread.java:748) java.util.ConcurrentModificationException at java.util.ArrayListItr.checkForComodification(ArrayList.java:909)
at java.util.ArrayListItr.next(ArrayList.java:859)atjava.util.AbstractCollection.toString(AbstractCollection.java:461)atjava.lang.String.valueOf(String.java:2994)atjava.io.PrintStream.println(PrintStream.java:821)atexample.Main.lambdaItr.next(ArrayList.java:859) at java.util.AbstractCollection.toString(AbstractCollection.java:461) at java.lang.String.valueOf(String.java:2994) at java.io.PrintStream.println(PrintStream.java:821) at example.Main.lambdamain0(Main.java:19)atjava.lang.Thread.run(Thread.java:748)java.util.ConcurrentModificationExceptionatjava.util.ArrayList0(Main.java:19) at java.lang.Thread.run(Thread.java:748) java.util.ConcurrentModificationException at java.util.ArrayListItr.checkForComodification(ArrayList.java:909)
at java.util.ArrayListItr.next(ArrayList.java:859)atjava.util.AbstractCollection.toString(AbstractCollection.java:461)atjava.lang.String.valueOf(String.java:2994)atjava.io.PrintStream.println(PrintStream.java:821)atexample.Main.lambdaItr.next(ArrayList.java:859) at java.util.AbstractCollection.toString(AbstractCollection.java:461) at java.lang.String.valueOf(String.java:2994) at java.io.PrintStream.println(PrintStream.java:821) at example.Main.lambdamain0(Main.java:19)atjava.lang.Thread.run(Thread.java:748)java.util.ConcurrentModificationExceptionatjava.util.ArrayList0(Main.java:19) at java.lang.Thread.run(Thread.java:748) java.util.ConcurrentModificationException at java.util.ArrayListItr.checkForComodification(ArrayList.java:909)
at java.util.ArrayListItr.next(ArrayList.java:859)atjava.util.AbstractCollection.toString(AbstractCollection.java:461)atjava.lang.String.valueOf(String.java:2994)atjava.io.PrintStream.println(PrintStream.java:821)atexample.Main.lambdaItr.next(ArrayList.java:859) at java.util.AbstractCollection.toString(AbstractCollection.java:461) at java.lang.String.valueOf(String.java:2994) at java.io.PrintStream.println(PrintStream.java:821) at example.Main.lambdamain$0(Main.java:19)
at java.lang.Thread.run(Thread.java:748)

如何讓集合操作安全?

  1. vector
  2. List list = Collections.synchronizedList(new ArrayList<>());
  3. CopyOnWriteArrayList 或者其他的一些工具類
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章