java-實戰java高併發程序設計-ch3JDK併發包

JDK 併發包

參考:> https://github.com/chengbingh...java

3.1 多線程的同步協助:同步控制

3.1.1 synchronized 擴展功能:重入鎖
jdk1.5以前重入鎖ReentrantLook性能好於synchronized, 但jdk1.6 開始優化ReentrantLook, 如今兩者的性能相差不大。git

/**
 * @author ChengBing Han
 * @date 21:50  2018/6/23
 * @description
 */
public class ReentrantLockTest {
    static ReentrantLock reentrantLock = new ReentrantLock();
    static final Object obj = new Object();
    public static void main(String[] args) throws InterruptedException {

        final Thread t1 = new Thread(new Runnable() {
            public void run() {
                System.out.println("T1 lock1");
                reentrantLock.lock();
                System.out.println("T1 lock2");
                reentrantLock.lock();
                System.out.println("T1 unlock1");

                reentrantLock.unlock();
                System.out.println("T1 unlock2");
                reentrantLock.unlock();
            }
        });


        final Thread t2 = new Thread(new Runnable() {
            public void run() {
                synchronized (obj){
                    System.out.println("t2 lock1");
                    synchronized (obj){
                        System.out.println("t2 lock2 ");

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

        });

        System.out.println("lock============");
        t1.start();
        Thread.sleep(1000);
        System.out.println("syschronized==================");
        t2.start();


    }


}

輸出:
lock============
T1 lock1
T1 lock2
T1 unlock1
T1 unlock2
syschronized==================
t2 lock1
t2 lock2 
t2 end

中斷響應github

public class Interrupted implements Runnable {
    private  Integer state = 0;

    public Interrupted() {
    }

    public Interrupted(Integer state) {
        this.state = state;
    }
   static ReentrantLock reentrantLock1 = new ReentrantLock();
   static ReentrantLock reentrantLock2 = new ReentrantLock();

    public void run() {

        try {
            if(state == 1) {
                reentrantLock1.lockInterruptibly();
                System.out.println("state1===lock1");
                Thread.sleep(1000);
                reentrantLock2.lockInterruptibly();
                System.out.println("state1===lock2");

            }else if(state == 2){
                reentrantLock2.lockInterruptibly();
                System.out.println("state2===lock2");
                Thread.sleep(1000);

                reentrantLock1.lockInterruptibly();
                System.out.println("state2===lock1");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            if(reentrantLock1.isHeldByCurrentThread()){
                reentrantLock1.unlock();
            }
            if(reentrantLock2.isHeldByCurrentThread()){
                reentrantLock2.unlock();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        final Interrupted r1 = new Interrupted(1);
        final Interrupted r2 = new Interrupted(2);
        final Thread t1 = new Thread(r1);
        final Thread t2 = new Thread(r2);

        t1.start();
        Thread.sleep(100);
        t2.start();
        Thread.sleep(5000);

        t2.interrupt();
    }
}
輸出
state1===lock1
state2===lock2
java.lang.InterruptedException
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
    at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
    at com.hcb.thread.c3_1_retrantlookinterrupted.Interrupted.run(Interrupted.java:39)
    at java.lang.Thread.run(Thread.java:748)
state1===lock2

鎖申請等待限時
一個鎖只能鎖住某個時間段數據庫

public class TimeLock implements Runnable{

    static ReentrantLock reentrantLock = new ReentrantLock();
    public void run() {

        try {
            if(reentrantLock.tryLock(3, TimeUnit.SECONDS)){
                System.out.println(Thread.currentThread().getName() + " run");
                Thread.sleep(6000);

            }else {
                System.out.println(Thread.currentThread().getName() + "getLock failed");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            //注意finally 這裏釋放鎖的方式
            if(reentrantLock.isHeldByCurrentThread()){
                reentrantLock.unlock();
            }
        }


    }
    
    public static void main(String[] args) throws InterruptedException {
        final TimeLock r1 = new TimeLock();

        final Thread thread1 = new Thread(r1);
        thread1.setName("t1");
        thread1.start();
        Thread.sleep(100);

        final TimeLock r2 = new TimeLock();
        final Thread thread2 = new Thread(r2);
        thread2.setName("t2");
        thread2.start();

    }
}

公平鎖多線程

public class FairLock {

    //構造函數爲true,表示公平
    static ReentrantLock reentrantLock = new ReentrantLock(true);
    
    public static class ThreadFair implements Runnable {
        public void run() {
            while (true) {
                try {
                    reentrantLock.lockInterruptibly();
                    System.out.println(Thread.currentThread().getName() + "  run  ");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    if (reentrantLock.isHeldByCurrentThread()) {
                        reentrantLock.unlock();
                    }
                }
            }

        }
    }

    public static void main(String[] args) {
       
            final ThreadFair threadFair = new ThreadFair();
            final Thread fairThread1 = new Thread(threadFair, "fairThread1");
            final ThreadFair threadFair2 = new ThreadFair();
            final Thread fairThread2 = new Thread(threadFair2, "fairThread2");

            fairThread1.start();
            fairThread2.start();
            

    }

}

output:
fairThread1  run  
fairThread2  run  
fairThread1  run  
fairThread2  run  
fairThread1  run  
fairThread2  run  
fairThread1  run  
fairThread2  run  
fairThread1  run  
fairThread2  run  
fairThread1  run  
fairThread2  run  
fairThread1  run  
fairThread2  run

重入鎖的condition條件併發

Condition條件相似與wait,notify方法
備註:Condition的使用注意
一、必須在lock.lock()
和lock.singXX中使用 await/singXXapp

二、方法名是await 不是wait,wait 是object的方法
clipboard.png函數

public class ConditionLock {
    static ReentrantLock reentrantLock = new ReentrantLock();
    static Condition condition = reentrantLock.newCondition();


    static class ConditionLockThread implements Runnable {

        public void run() {

            reentrantLock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + " wait...");
                //方法是await不是object的wait
                condition.await();
                System.out.println(Thread.currentThread().getName() + " end wait...");


            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                if(reentrantLock.isHeldByCurrentThread()){
                    reentrantLock.unlock();
                }

            }

        }
    }

    public static void main(String[] args) throws InterruptedException {
        final ConditionLockThread conditionLockThread1 = new ConditionLockThread();
        final Thread thread1 = new Thread(conditionLockThread1, "ConditionLockThread1");

        final ConditionLockThread conditionLockThread2 = new ConditionLockThread();
        final Thread thread2 = new Thread(conditionLockThread2, "ConditionLockThread2");

        thread1.start();

        thread2.start();
        Thread.sleep(1000);
        //必須在 lock.lock/unlock 中間使用
        reentrantLock.lock();
        condition.signalAll();
        reentrantLock.unlock();

    }
}

容許多個線程同時訪問 信號量Semaphore
能夠容許n個線程同時訪問,結合公平鎖。工具

clipboard.png

3.1.4 讀寫鎖
ReadWriteLock JDK性能

/**
 * @author ChengBing Han
 * @date 14:44  2018/7/7
 * @description
 */
public class ReadWriteLockDemo {
    public static ReentrantLock lock = new ReentrantLock();
    private static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
    public static Lock readLock = reentrantReadWriteLock.readLock();
    public static Lock writeLock = reentrantReadWriteLock.writeLock();
    public static int value;

    private static int index = 0;

    public static Object handleRead(Lock lock) {

        lock.lock();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        System.out.println("read value is " + value);
        return value;
    }

    public static void handleWrite(Lock lock, int newValue) {
        lock.lock();

        try {
            Thread.sleep(1000);
            value = newValue;
            System.out.println("write value is " + value);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }


    public static void main(String[] args) {


        final long startTime = System.currentTimeMillis();


        final Runnable readRunnable = new Runnable() {
            public void run() {
                handleRead(readLock);
            }
        };


        final Runnable writeRunnable = new Runnable() {
            public void run() {

                handleWrite(writeLock, ++index);
            }
        };

        for (int i = 0; i < 10; i++) {
            final Thread thread = new Thread(readRunnable);
            thread.start();
        }

        for (int i = 0; i < 10; i++) {
            final Thread thread = new Thread(writeRunnable);
            thread.start();

        }

        //爲何要在while中輸出一些東西呢
        //若是仍是一個空的While循環,while 會被優化在-Server模式下
        while (value != 10){
            System.out.print("");
        }

        final long end = System.currentTimeMillis();
        System.out.println("app use :" + (end - startTime)/1000);

    }
}

倒計時(線程個數)器: CountDownLatch
可讓n線程都完成任務了,在繼續執行某個主線程。例如,火箭發射前有10個檢查任務,這時建立10個線程分別處理十個任務,再建立一個發射火箭的線程,每次完成一個檢查任務,CountDownLatch 記錄一個,這樣,能夠等10個都完成了,發射火箭的線程再執行。

倒計時器的擴展:循柵欄。
擴展了CountDownLatch,將軍讓10個士兵爲1組, 這樣一組的完成相似於CountDownLatch, 若是與多組就用循環柵欄。 能夠循環多組。

線程阻塞工具類:LockSupport
提供一些阻塞的功能

3.2 線程複用:線程池

3.2.1什麼是線程池
同數據庫鏈接池
3.3.2不要重複造輪子:jdk對線程池的支持

clipboard.png

Executors 是什麼?
一言蔽之:工廠

Executors的介紹:
/**
 * Factory and utility methods for {@link Executor}, {@link
 * ExecutorService}, {@link ScheduledExecutorService}, {@link
 * ThreadFactory}, and {@link Callable} classes defined in this
 * package. This class supports the following kinds of methods:
 *
 * <ul>
 *   <li> Methods that create and return an {@link ExecutorService}
 *        set up with commonly useful configuration settings.
 *   <li> Methods that create and return a {@link ScheduledExecutorService}
 *        set up with commonly useful configuration settings.
 *   <li> Methods that create and return a "wrapped" ExecutorService, that
 *        disables reconfiguration by making implementation-specific methods
 *        inaccessible.
 *   <li> Methods that create and return a {@link ThreadFactory}
 *        that sets newly created threads to a known state.
 *   <li> Methods that create and return a {@link Callable}
 *        out of other closure-like forms, so they can be used
 *        in execution methods requiring {@code Callable}.
 * </ul>
 *
 * @since 1.5
 * @author Doug Lea
 */

clipboard.png

clipboard.png

線程池說明

clipboard.png

固定數量的線程池
弊端:若是線程池中有5個任務,第一個任務

/**
 * @author ChengBing Han
 * @date 12:19  2018/7/14
 * @description
 */
public class FixThreadPoolTest {
    
    public static class MyTask implements Runnable{
        public void run() {
            final long id = Thread.currentThread().getId();
            System.out.println("當前線程的id是: "  + id);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
    
    public static void main(String[] args) {
        final ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            newFixedThreadPool.submit(new MyTask());
        }
    }
}
經過輸出能夠看到,10個任務,用池子中的了5個線程
**output:**
當前線程的id是: 13
當前線程的id是: 15
當前線程的id是: 16
當前線程的id是: 13
當前線程的id是: 14
當前線程的id是: 17
當前線程的id是: 15
當前線程的id是: 16
當前線程的id是: 13
當前線程的id是: 14

異常處理

/**
 * @author ChengBing Han
 * @date 12:19  2018/7/14
 * @description
 */
public class FixThreadPoolTest {

    static boolean flag = true;
    
    public static class MyTask implements Runnable{
        public void run() {
            if(flag){
                flag=false;
                System.out.println("出現異常");
                System.out.println(1/0);
                System.out.println("異常結束");
            }

            final long id = Thread.currentThread().getId();
            System.out.println("當前線程的id是: "  + id);
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

    public static void main(String[] args) {
        final ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            newFixedThreadPool.submit(new MyTask());
        }
        newFixedThreadPool.shutdown();
    }
}


output:
出現異常
當前線程的id是: 11
當前線程的id是: 14
當前線程的id是: 15
當前線程的id是: 13
當前線程的id是: 12
當前線程的id是: 14
當前線程的id是: 15
當前線程的id是: 11
當前線程的id是: 13

**結論:根據上述輸出,能夠發現,線程次中有10次調用,某次發生異常,不會影響其它的9次**

定時線程:

/**
 * @author ChengBing Han
 * @date 12:24  2018/7/14
 * @description
 */
public class SheduleThreadPoolTest {
    
    public static class MyTask implements Runnable{

        public void run() {
            System.out.println("Thread is run which  id is : " + Thread.currentThread().getId());
        }
    }

    public static void main(String[] args) {
        final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
        scheduledExecutorService.scheduleAtFixedRate(new MyTask(),10,1,TimeUnit.SECONDS);
    }
}

*注意定時的這個線程池和上述的newFixedThreadPool不一樣,一旦某個任務出現調度異常,那麼後面的任務都不會再執行。==》作好異常處理工做。

*定時任務的兩個方法不一樣之處在於
scheduleAtFixedRate: 每隔2秒調度一個任務,可是一個任務的時間是8秒(大於2秒)那麼實際是8秒調度一個任務。
scheduleWithFixedDelay: 隔2秒調度一個任務,可是一個任務的時間是8秒(大於2秒)那麼實際是8+2秒調度一個任務。

3.2.3 線程池的內部實現:該部分待看書

相關文章
相關標籤/搜索