亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

小馬哥Java面試題課程總結(jié)

FingerLiu / 2932人閱讀

摘要:無(wú)限期等待另一個(gè)線程執(zhí)行特定操作。線程安全基本版請(qǐng)說(shuō)明以及的區(qū)別值都不能為空數(shù)組結(jié)構(gòu)上,通過(guò)數(shù)組和鏈表實(shí)現(xiàn)。優(yōu)先考慮響應(yīng)中斷,而不是響應(yīng)鎖的普通獲取或重入獲取。只是在最后獲取鎖成功后再把當(dāng)前線程置為狀態(tài)然后再中斷線程。

前段時(shí)間在慕課網(wǎng)直播上聽(tīng)小馬哥面試勸退("面試虐我千百遍,Java 并發(fā)真討厭"),發(fā)現(xiàn)講得東西比自己拿到offer還要高興,于是自己在線下做了一點(diǎn)小筆記,供各位參考。

課程地址:https://www.bilibili.com/vide...

源碼文檔地址:https://github.com/mercyblitz...

本文來(lái)自于我的慕課網(wǎng)手記:小馬哥Java面試題課程總結(jié),轉(zhuǎn)載請(qǐng)保留鏈接 ;)
Java 多線程 1、線程創(chuàng)建 基本版

有哪些方法創(chuàng)建線程?

僅僅只有new thread這種方法創(chuàng)建線程

public class ThreadCreationQuestion {

    public static void main(String[] args) {
        // main 線程 -> 子線程
        Thread thread = new Thread(() -> {
        }, "子線程-1");

    }

    /**
     * 不鼓勵(lì)自定義(擴(kuò)展) Thread
     */
    private static class MyThread extends Thread {

        /**
         * 多態(tài)的方式,覆蓋父類實(shí)現(xiàn)
         */
        @Override
        public void run(){
            super.run();
        }
    }

}

與運(yùn)行線程方法區(qū)分:
java.lang.Runnable()java.lang.Thread類

進(jìn)階版

如何通過(guò)Java 創(chuàng)建進(jìn)程?

public class ProcessCreationQuestion {

    public static void main(String[] args) throws IOException {

        // 獲取 Java Runtime
        Runtime runtime = Runtime.getRuntime();
        Process process = runtime.exec("cmd /k start http://www.baidu.com");
        process.exitValue();
    }
}
勸退版

如何銷毀一個(gè)線程?

public class ThreadStateQuestion {


    public static void main(String[] args) {

        // main 線程 -> 子線程
        Thread thread = new Thread(() -> { // new Runnable(){ public void run(){...}};
            System.out.printf("線程[%s] 正在執(zhí)行...
", Thread.currentThread().getName());  // 2
        }, "子線程-1");

        // 啟動(dòng)線程
        thread.start();

        // 先于 Runnable 執(zhí)行
        System.out.printf("線程[%s] 是否還活著: %s
", thread.getName(), thread.isAlive()); // 1
        // 在 Java 中,執(zhí)行線程 Java 是沒(méi)有辦法銷毀它的,
        // 但是當(dāng) Thread.isAlive() 返回 false 時(shí),實(shí)際底層的 Thread 已經(jīng)被銷毀了
    }

Java代碼中是無(wú)法實(shí)現(xiàn)的,只能表現(xiàn)一個(gè)線程的狀態(tài)。

而CPP是可以實(shí)現(xiàn)的。

2、線程執(zhí)行 基本版

如何通過(guò) Java API 啟動(dòng)線程?

thread.start();

進(jìn)階版

當(dāng)有線程 T1、T2 以及 T3,如何實(shí)現(xiàn)T1 -> T2 -> T3的執(zhí)行順序?

private static void threadJoinOneByOne() throws InterruptedException {
        Thread t1 = new Thread(ThreadExecutionQuestion::action, "t1");
        Thread t2 = new Thread(ThreadExecutionQuestion::action, "t2");
        Thread t3 = new Thread(ThreadExecutionQuestion::action, "t3");

        // start() 僅是通知線程啟動(dòng)
        t1.start();
        // join() 控制線程必須執(zhí)行完成
        t1.join();

        t2.start();
        t2.join();

        t3.start();
        t3.join();
    }

    private static void action() {
        System.out.printf("線程[%s] 正在執(zhí)行...
", Thread.currentThread().getName());  // 2
    }
}

CountDownLatch也可以實(shí)現(xiàn);

調(diào)整優(yōu)先級(jí)并不能保證優(yōu)先級(jí)高的線程先執(zhí)行。

勸退版

以上問(wèn)題請(qǐng)至少提供另外一種實(shí)現(xiàn)?(1.5)

1、spin 方法

    private static void threadLoop() {

        Thread t1 = new Thread(ThreadExecutionQuestion::action, "t1");
        Thread t2 = new Thread(ThreadExecutionQuestion::action, "t2");
        Thread t3 = new Thread(ThreadExecutionQuestion::action, "t3");

        t1.start();

        while (t1.isAlive()) {
            // 自旋 Spin
        }

        t2.start();

        while (t2.isAlive()) {

        }

        t3.start();

        while (t3.isAlive()) {

        }
    }

2、sleep 方法

 private static void threadSleep() throws InterruptedException {

        Thread t1 = new Thread(ThreadExecutionQuestion::action, "t1");
        Thread t2 = new Thread(ThreadExecutionQuestion::action, "t2");
        Thread t3 = new Thread(ThreadExecutionQuestion::action, "t3");

        t1.start();

        while (t1.isAlive()) {
            // sleep
            Thread.sleep(0);
        }

        t2.start();

        while (t2.isAlive()) {
            Thread.sleep(0);
        }

        t3.start();

        while (t3.isAlive()) {
            Thread.sleep(0);
        }

    }

3、while 方法

    private static void threadWait() throws InterruptedException {

        Thread t1 = new Thread(ThreadExecutionQuestion::action, "t1");
        Thread t2 = new Thread(ThreadExecutionQuestion::action, "t2");
        Thread t3 = new Thread(ThreadExecutionQuestion::action, "t3");

        threadStartAndWait(t1);
        threadStartAndWait(t2);
        threadStartAndWait(t3);
    }

    private static void threadStartAndWait(Thread thread) {

        if (Thread.State.NEW.equals(thread.getState())) {
            thread.start();
        }

        while (thread.isAlive()) {
            synchronized (thread) {
                try {
                    thread.wait(); // 到底是誰(shuí)通知 Thread -> thread.notify();  JVM幫它喚起
                                  // LockSupport.park(); 
                                 // 死鎖發(fā)生
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
3、線程終止 基本版

如何停止一個(gè)線程?

public class HowToStopThreadQuestion {

    public static void main(String[] args) throws InterruptedException {

        Action action = new Action();

        // 方法一
        Thread t1 = new Thread(action, "t1");

        t1.start();

        // 改變 action stopped 狀態(tài)
        action.setStopped(true);

        t1.join();

        // 方法二
        Thread t2 = new Thread(() -> {
            if (!Thread.currentThread().isInterrupted()) {
                action();
            }
        }, "t2");

        t2.start();
        // 中斷操作(僅僅設(shè)置狀態(tài),而并非中止線程)
        t2.interrupt();
        t2.join();
    }


    private static class Action implements Runnable {

        // 線程安全問(wèn)題,確??梢?jiàn)性(Happens-Before)
        private volatile boolean stopped = false;

        @Override
        public void run() {
            if (!stopped) {
                // 執(zhí)行動(dòng)作
                action();
            }
        }

        public void setStopped(boolean stopped) {

            this.stopped = stopped;
        }
    }

    private static void action() {
        System.out.printf("線程[%s] 正在執(zhí)行...
", Thread.currentThread().getName());  // 2
    }
}

想要停止一個(gè)線程是不可能的,真正的只能停止邏輯。

進(jìn)階版

為什么 Java 要放棄 Thread 的 stop()方法?

Because it is inherently unsafe. Stopping a thread causes it to unlock all the monitors that it has locked.(The monitors are unlocked as the ThreadDeath exception propagates up the stack.) If any of the objects previously protected by these monitors were in an inconsistent state, other threads may now view these objects in an inconsistent state. Such objects are said to be damaged. When threads operate on damaged objects, arbitrary behavior can result. This behavior may be subtle and difficult to detect, or it may be pronounced. Unlike other unchecked exceptions, ThreadDeath kills threads silently; thus, the user has no warning that his program may be corrupted. The corruption can manifest itself at any time after the actual damage occurs, even hours or days in the future.

Why is Thread.stop deprecated?

簡(jiǎn)單的說(shuō),防止死鎖,以及狀態(tài)不一致的情況出現(xiàn)。

勸退版

請(qǐng)說(shuō)明 Thread interrupt()、isInterrupted() 以及 interrupted()的區(qū)別以及意義?

Thread interrupt(): 設(shè)置狀態(tài),調(diào)JVM的本地(native)interrupt0()方法。

    public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();  // Just to set the interrupt flag
                              //--> private native void interrupt0();
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }

isInterrupted(): 調(diào)的是靜態(tài)方法isInterrupted(),當(dāng)且僅當(dāng)狀態(tài)設(shè)置為中斷時(shí),返回false,并不清除狀態(tài)。

  public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }

    /**
     * Tests whether this thread has been interrupted.  The interrupted
     * status of the thread is unaffected by this method.
     *
     * 

A thread interruption ignored because a thread was not alive * at the time of the interrupt will be reflected by this method * returning false. * * @return true if this thread has been interrupted; * false otherwise. * @see #interrupted() * @revised 6.0 */ public boolean isInterrupted() { return isInterrupted(false); }

interrupted(): 私有本地方法,即判斷中斷狀態(tài),又清除狀態(tài)。

 private native boolean isInterrupted(boolean ClearInterrupted);
4、線程異常 基本版

當(dāng)線程遇到異常時(shí),到底發(fā)生了什么?

線程會(huì)掛

public class ThreadExceptionQuestion {

    public static void main(String[] args) throws InterruptedException {
        //...
        // main 線程 -> 子線程
        Thread t1 = new Thread(() -> {
            throw new RuntimeException("數(shù)據(jù)達(dá)到閾值");
        }, "t1");

        t1.start();
        // main 線程會(huì)中止嗎?
        t1.join();

        // Java Thread 是一個(gè)包裝,它由 GC 做垃圾回收
        // JVM Thread 可能是一個(gè) OS Thread,JVM 管理,
        // 當(dāng)線程執(zhí)行完畢(正?;蛘弋惓#?        System.out.println(t1.isAlive());
    }
}
進(jìn)階版

當(dāng)線程遇到異常時(shí),如何捕獲?

...
        Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
            System.out.printf("線程[%s] 遇到了異常,詳細(xì)信息:%s
",
                    thread.getName(),
                    throwable.getMessage());
        });
...
勸退版

當(dāng)線程遇到異常時(shí),ThreadPoolExecutor 如何捕獲異常?

public class ThreadPoolExecutorExceptionQuestion {

    public static void main(String[] args) throws InterruptedException {

//        ExecutorService executorService = Executors.newFixedThreadPool(2);

        ThreadPoolExecutor executorService = new ThreadPoolExecutor(
                1,
                1,
                0,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>()
        ) {

            /**
             * 通過(guò)覆蓋 {@link ThreadPoolExecutor#afterExecute(Runnable, Throwable)} 達(dá)到獲取異常的信息
             * @param r
             * @param t
             */
            @Override
            protected void afterExecute(Runnable r, Throwable t) {
                System.out.printf("線程[%s] 遇到了異常,詳細(xì)信息:%s
",
                        Thread.currentThread().getName(),
                        t.getMessage());
            }

        };

        executorService.execute(() -> {
            throw new RuntimeException("數(shù)據(jù)達(dá)到閾值");
        });

        // 等待一秒鐘,確保提交的任務(wù)完成
        executorService.awaitTermination(1, TimeUnit.SECONDS);

        // 關(guān)閉線程池
        executorService.shutdown();

    }
}
5、線程狀態(tài) 基本版

Java 線程有哪些狀態(tài),分別代表什么含義?

NEW: Thread state for a thread which has not yet started.

未啟動(dòng)的。不會(huì)出現(xiàn)在Dump中。

RUNNABLE: Thread state for a runnable thread. A thread in the runnable state is executing in the Java virtual machine, but it may be waiting for other resources from the operating system such as processor.

在虛擬機(jī)內(nèi)執(zhí)行的。運(yùn)行中狀態(tài),可能里面還能看到locked字樣,表明它獲得了某把鎖。

BLOCKE: Thread state for a thread blocked waiting for a monitor lock. A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized block/method after calling {@link Object#wait() Object.wait}.

受阻塞并等待監(jiān)視器鎖。被某個(gè)鎖(synchronizers)給block住了。

WAITING: Thread state for a waiting thread. A thread is in the waiting state due to calling one of the following methods:

  • {@link Object#wait() Object.wait} with no timeout
  • {@link #join() Thread.join} with no timeout
  • {@link LockSupport#park() LockSupport.park}

A thread in the waiting state is waiting for another thread to perform a particular action.

For example, a thread that has called Object.wait() on an object is waiting for another thread to call Object.notify() or Object.notifyAll() on that object. A thread that has called Thread.join() is waiting for a specified thread to terminate.

無(wú)限期等待另一個(gè)線程執(zhí)行特定操作。等待某個(gè)condition或monitor發(fā)生,一般停留在park(), wait(), sleep(),join() 等語(yǔ)句里。

TIMED_WAITING: Thread state for a waiting thread with a specified waiting time. A thread is in the timed waiting state due to calling one of the following methods with a specified positive waiting time:

  • {@link #sleep Thread.sleep}
  • {@link Object#wait(long) Object.wait} with timeout
  • {@link #join(long) Thread.join} with timeout
  • {@link LockSupport#parkNanos LockSupport.parkNanos}
  • {@link LockSupport#parkUntil LockSupport.parkUntil}

有時(shí)限的等待另一個(gè)線程的特定操作。和WAITING的區(qū)別是wait() 等語(yǔ)句加上了時(shí)間限制 wait(timeout)。

TERMINATED: 已退出的; Thread state for a terminated thread. The thread has completed execution.

進(jìn)階版

如何獲取當(dāng)前JVM 所有的現(xiàn)場(chǎng)狀態(tài)?

方法一:命令

jstack: jstack用于打印出給定的java進(jìn)程ID或core file或遠(yuǎn)程調(diào)試服務(wù)的Java堆棧信息。主要用來(lái)查看Java線程的調(diào)用堆棧的,可以用來(lái)分析線程問(wèn)題(如死鎖)。

jsp

jsp [option/ -l] pid

方法二:ThreadMXBean

public class AllThreadStackQuestion {

    public static void main(String[] args) {
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        long[] threadIds = threadMXBean.getAllThreadIds();

        for (long threadId : threadIds) {
            ThreadInfo threadInfo = threadMXBean.getThreadInfo(threadId);
            System.out.println(threadInfo.toString());
        }

    }
}
勸退版

如何獲取線程的資源消費(fèi)情況?

public class AllThreadInfoQuestion {

    public static void main(String[] args) {
        ThreadMXBean threadMXBean = (ThreadMXBean) ManagementFactory.getThreadMXBean();
        long[] threadIds = threadMXBean.getAllThreadIds();

        for (long threadId : threadIds) {
//            ThreadInfo threadInfo = threadMXBean.getThreadInfo(threadId);
//            System.out.println(threadInfo.toString());
            long bytes = threadMXBean.getThreadAllocatedBytes(threadId);
            long kBytes = bytes / 1024;
            System.out.printf("線程[ID:%d] 分配內(nèi)存: %s KB
", threadId, kBytes);
        }

    }
}
6、線程同步 基本版

請(qǐng)說(shuō)明 synchronized 關(guān)鍵字在修飾方法與代碼塊中的區(qū)別?

字節(jié)碼的區(qū)別 (一個(gè)monitor,一個(gè)synchronized關(guān)鍵字)

public class SynchronizedKeywordQuestion {

    public static void main(String[] args) {

    }

    private static void synchronizedBlock() {
        synchronized (SynchronizedKeywordQuestion.class) {
        }
    }

    private synchronized static void synchronizedMethod() {
    }
}
進(jìn)階版

請(qǐng)說(shuō)明 synchronized 關(guān)鍵字與 ReentrantLock 之間的區(qū)別?

兩者都是可重入鎖

synchronized 依賴于 JVM 而 ReentrantLock 依賴于 API

ReentrantLock 比 synchronized 增加了一些高級(jí)功能

相比synchronized,ReentrantLock增加了一些高級(jí)功能。主要來(lái)說(shuō)主要有三點(diǎn):①等待可中斷;②可實(shí)現(xiàn)公平鎖;③可實(shí)現(xiàn)選擇性通知(鎖可以綁定多個(gè)條件)

兩者的性能已經(jīng)相差無(wú)幾

談?wù)?synchronized 和 ReentrantLock 的區(qū)別

勸退版

請(qǐng)解釋偏向鎖對(duì) synchronized 與 ReentrantLock 的價(jià)值?

偏向鎖只對(duì) synchronized 有用,而 ReentrantLock 已經(jīng)實(shí)現(xiàn)了偏向鎖。

Synchronization and Object Locking

7、線程通訊 基本版

為什么 wait() 和 notify() 以及 notifyAll() 方法屬于 Object ,并解釋它們的作用?

Java所有對(duì)象都是來(lái)自 Object

wait():

notify():

notifyAll():

進(jìn)階版

為什么 Object wait() notify() 以及 notifyAll() 方法必須 synchronized 之中執(zhí)行?

wait(): 獲得鎖的對(duì)象,釋放鎖,當(dāng)前線程又被阻塞,等同于Java 5 LockSupport 中的park方法

notify(): 已經(jīng)獲得鎖,喚起一個(gè)被阻塞的線程,等同于Java 5 LockSupport 中的unpark()方法

notifyAll():

勸退版

請(qǐng)通過(guò) Java 代碼模擬實(shí)現(xiàn) wait() 和 notify() 以及 notifyAll() 的語(yǔ)義?

8、線程退出 基本版

當(dāng)主線程退出時(shí),守護(hù)線程會(huì)執(zhí)行完畢嗎?

不一定執(zhí)行完畢

public class DaemonThreadQuestion {

    public static void main(String[] args) {
        // main 線程
        Thread t1 = new Thread(() -> {
            System.out.println("Hello,World");
//            Thread currentThread = Thread.currentThread();
//            System.out.printf("線程[name : %s, daemon:%s]: Hello,World
",
//                    currentThread.getName(),
//                    currentThread.isDaemon()
//            );
        }, "daemon");
        // 編程守候線程
        t1.setDaemon(true);
        t1.start();

        // 守候線程的執(zhí)行依賴于執(zhí)行時(shí)間(非唯一評(píng)判)
    }
}
進(jìn)階版

請(qǐng)說(shuō)明 ShutdownHook 線程的使用場(chǎng)景,以及如何觸發(fā)執(zhí)行?

public class ShutdownHookQuestion {

    public static void main(String[] args) {

        Runtime runtime = Runtime.getRuntime();

        runtime.addShutdownHook(new Thread(ShutdownHookQuestion::action, "Shutdown Hook Question"));

    }

    private static void action() {
        System.out.printf("線程[%s] 正在執(zhí)行...
", Thread.currentThread().getName());  // 2
    }
}

使用場(chǎng)景:Spring 中 AbstractApplicationContext 的 registerShutdownHook()

勸退版

如何確保主線程退出前,所有線程執(zhí)行完畢?

public class CompleteAllThreadsQuestion {

    public static void main(String[] args) throws InterruptedException {

        // main 線程 -> 子線程
        Thread t1 = new Thread(CompleteAllThreadsQuestion::action, "t1");
        Thread t2 = new Thread(CompleteAllThreadsQuestion::action, "t2");
        Thread t3 = new Thread(CompleteAllThreadsQuestion::action, "t3");

        // 不確定 t1、t2、t3 是否調(diào)用 start()

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

        // 創(chuàng)建了 N Thread

        Thread mainThread = Thread.currentThread();
        // 獲取 main 線程組
        ThreadGroup threadGroup = mainThread.getThreadGroup();
        // 活躍的線程數(shù)
        int count = threadGroup.activeCount();
        Thread[] threads = new Thread[count];
        // 把所有的線程復(fù)制 threads 數(shù)組
        threadGroup.enumerate(threads, true);

        for (Thread thread : threads) {
            System.out.printf("當(dāng)前活躍線程: %s
", thread.getName());
        }
    }

    private static void action() {
        System.out.printf("線程[%s] 正在執(zhí)行...
", Thread.currentThread().getName());  // 2
    }

}
Java 并發(fā)集合框架 1、線程安全集合 基本版

請(qǐng)?jiān)?Java 集合框架以及 J.U.C 框架中各列舉出 List、Set 以及 Map 的實(shí)現(xiàn)?

Java 集合框架: LinkedList、ArrayList、HashSet、TreeSet、HashMap

J.U.C 框架: CopyOnWriteArrayList、CopyOnWriteArraySet、ConcurrentSkipListSet、ConcurrentSkipListMap、ConcurrentHashMap

進(jìn)階版

如何將普通 List、Set 以及 Map 轉(zhuǎn)化為線程安全對(duì)象?

public class ThreadSafeCollectionQuestion {

    public static void main(String[] args) {

        List list = Arrays.asList(1, 2, 3, 4, 5);

        Set set = Set.of(1, 2, 3, 4, 5);

        Map map = Map.of(1, "A");

        // 以上實(shí)現(xiàn)都是不變對(duì)象,不過(guò)第一個(gè)除外

        // 通過(guò) Collections#sychronized* 方法返回

        // Wrapper 設(shè)計(jì)模式(所有的方法都被 synchronized 同步或互斥)
        list = Collections.synchronizedList(list);

        set = Collections.synchronizedSet(set);

        map = Collections.synchronizedMap(map);

    }
}
勸退版

如何在 Java 9+ 實(shí)現(xiàn)以上問(wèn)題?

public class ThreadSafeCollectionQuestion {

    public static void main(String[] args) {

        // Java 9 的實(shí)現(xiàn)
        List list = Arrays.asList(1, 2, 3, 4, 5);

        // Java 9 + of 工廠方法,返回 Immutable 對(duì)象

        list = List.of(1, 2, 3, 4, 5);

        Set set = Set.of(1, 2, 3, 4, 5);

        Map map = Map.of(1, "A");

        // 以上實(shí)現(xiàn)都是不變對(duì)象,不過(guò)第一個(gè)除外

        // 通過(guò) Collections#sychronized* 方法返回

        // Wrapper 設(shè)計(jì)模式(所有的方法都被 synchronized 同步或互斥)
        list = Collections.synchronizedList(list);

        set = Collections.synchronizedSet(set);

        map = Collections.synchronizedMap(map);

        //
        list = new CopyOnWriteArrayList<>(list);
        set = new CopyOnWriteArraySet<>(set);
        map = new ConcurrentHashMap<>(map);

    }
}
2、線程安全 LIST 基本版

請(qǐng)說(shuō)明 List、Vector 以及 CopyOnWriteArrayList 的相同點(diǎn)和不同點(diǎn)?

相同點(diǎn):

Vector、CopyOnWriteArrayList 是 List 的實(shí)現(xiàn)。

不同點(diǎn):

Vector 是同步的,任何時(shí)候不加鎖。并且在設(shè)計(jì)中有個(gè) interator ,返回的對(duì)象是 fail-fast

CopyOnWriteArrayList 讀的時(shí)候是不加鎖;弱一致性,while true的時(shí)候不報(bào)錯(cuò)。

進(jìn)階版

請(qǐng)說(shuō)明 Collections#synchromizedList(List) 與 Vector 的相同點(diǎn)和不同點(diǎn)?

相同點(diǎn):

都是synchromized 的實(shí)現(xiàn)方式。

不同點(diǎn):

synchromized 返回的是list, 實(shí)現(xiàn)原理方式是 Wrapper 實(shí)現(xiàn);

而 Vector 是 List 的實(shí)現(xiàn)。實(shí)現(xiàn)原理方式是非 Wrapper 實(shí)現(xiàn)。

勸退版

Arrays#asList(Object...)方法是線程安全的嗎?如果不是的話,如果實(shí)現(xiàn)替代方案?

public class ArraysAsListMethodQuestion {

    public static void main(String[] args) {

        List list = Arrays.asList(1, 2, 3, 4, 5);
        // 調(diào)整第三個(gè)元素為 9
        list.set(2, 9);
        // 3 -> 9
        // Arrays.asList 并非線程安全
        list.forEach(System.out::println);
        // Java < 5 , Collections#synchronizedList
        // Java 5+ , CopyOnWriteArrayList
        // Java 9+ , List.of(...) 只讀
    }
}
3、線程安全 SET 基本版

請(qǐng)至少舉出三種線程安全的 Set 實(shí)現(xiàn)?

synchronizedSet、CopyOnWriteArraySet、ConcurrentSkipListSet

進(jìn)階版

在 J.U.C 框架中,存在HashSet 的線程安全實(shí)現(xiàn)?如果不存在的話,要如何實(shí)現(xiàn)?

不存在;

public class ConcurrentHashSetQuestion {


    public static void main(String[] args) {

    }

    private static class ConcurrentHashSet implements Set {

        private final Object OBJECT = new Object();

        private final ConcurrentHashMap map = new ConcurrentHashMap<>();

        private Set keySet() {
            return map.keySet();
        }

        @Override
        public int size() {
            return keySet().size();
        }

        @Override
        public boolean isEmpty() {
            return keySet().isEmpty();
        }

        @Override
        public boolean contains(Object o) {
            return keySet().contains(o);
        }

        @Override
        public Iterator iterator() {
            return keySet().iterator();
        }

        @Override
        public Object[] toArray() {
            return new Object[0];
        }

        @Override
        public  T[] toArray(T[] a) {
            return null;
        }

        @Override
        public boolean add(E e) {
            return map.put(e, OBJECT) == null;
        }

        @Override
        public boolean remove(Object o) {
            return map.remove(o) != null;
        }

        @Override
        public boolean containsAll(Collection c) {
            return false;
        }

        @Override
        public boolean addAll(Collection c) {
            return false;
        }

        @Override
        public boolean retainAll(Collection c) {
            return false;
        }

        @Override
        public boolean removeAll(Collection c) {
            return false;
        }

        @Override
        public void clear() {

        }
    }
}
勸退版

當(dāng) Set#iterator() 方法返回 Iterator 對(duì)象后,能否在其迭代中,給 Set 對(duì)象添加新的元素?

不一定;Set 在傳統(tǒng)實(shí)現(xiàn)中,會(huì)有fail-fast問(wèn)題;而在J.U.C中會(huì)出現(xiàn)弱一致性,對(duì)數(shù)據(jù)的一致性要求較低,是可以給 Set 對(duì)象添加新的元素。

4、線程安全 MAP 基本版

請(qǐng)說(shuō)明 Hashtable、HashMap 以及 ConcurrentHashMap 的區(qū)別?

Hashtable: key、value值都不能為空; 數(shù)組結(jié)構(gòu)上,通過(guò)數(shù)組和鏈表實(shí)現(xiàn)。

HashMap: key、value值都能為空;數(shù)組結(jié)構(gòu)上,當(dāng)閾值到達(dá)8時(shí),通過(guò)紅黑樹(shù)實(shí)現(xiàn)。

ConcurrentHashMap: key、value值都不能為空;數(shù)組結(jié)構(gòu)上,當(dāng)閾值到達(dá)8時(shí),通過(guò)紅黑樹(shù)實(shí)現(xiàn)。

HashMap和Hashtable的比較

進(jìn)階版

請(qǐng)說(shuō)明 ConcurrentHashMap 在不同的JDK 中的實(shí)現(xiàn)?

JDK 1.6中,采用分離鎖的方式,在讀的時(shí)候,部分鎖;寫的時(shí)候,完全鎖。而在JDK 1.7、1.8中,讀的時(shí)候不需要鎖的,寫的時(shí)候需要鎖的。并且JDK 1.8中在為了解決Hash沖突,采用紅黑樹(shù)解決。

HashMap? ConcurrentHashMap? 相信看完這篇沒(méi)人能難住你!

勸退版

請(qǐng)說(shuō)明 ConcurrentHashMap 與 ConcurrentSkipListMap 各自的優(yōu)勢(shì)與不足?

在 java 6 和 8 中,ConcurrentHashMap 寫的時(shí)候,是加鎖的,所以內(nèi)存占得比較小,而 ConcurrentSkipListMap 寫的時(shí)候是不加鎖的,內(nèi)存占得相對(duì)比較大,通過(guò)空間換取時(shí)間上的成本,速度較快,但比前者要慢,ConcurrentHashMap 基本上是常量時(shí)間。ConcurrentSkipListMap 讀和寫都是log N實(shí)現(xiàn),高性能相對(duì)穩(wěn)定。

5、線程安全 QUEUE 基本版

請(qǐng)說(shuō)明 BlockingQueue 與 Queue 的區(qū)別?

BlockingQueue 繼承了 Queue 的實(shí)現(xiàn);put 方法中有個(gè)阻塞的操作(InterruptedException),當(dāng)隊(duì)列滿的時(shí)候,put 會(huì)被阻塞;當(dāng)隊(duì)列空的時(shí)候,put方法可用。take 方法中,當(dāng)數(shù)據(jù)存在時(shí),才可以返回,否則為空。

進(jìn)階版

請(qǐng)說(shuō)明 LinkedBlockingQueue 與 ArrayBlockingQueue 的區(qū)別?

LinkedBlockingQueue 是鏈表結(jié)構(gòu);有兩個(gè)構(gòu)造器,一個(gè)是(Integer.MAX_VALUE),無(wú)邊界,另一個(gè)是(int capacity),有邊界;ArrayBlockingQueue 是數(shù)組結(jié)構(gòu);有邊界。

勸退版

請(qǐng)說(shuō)明 LinkedTransferQueue 與 LinkedBlockingQueue 的區(qū)別?

LinkedTransferQueue 是java 7中提供的新接口,性能比后者更優(yōu)化。

6、PRIORITYBLOCKINGQUEUE 請(qǐng)?jiān)u估以下程序的運(yùn)行結(jié)果?
public class priorityBlockingQueueQuiz{
    public static void main(String[] args) throw Exception {
        BlockingQueue queue = new PriorityBlockingQueue<>(2);
        // 1. PriorityBlockingQueue put(Object) 方法不阻塞,不拋異常
        // 2. PriorityBlockingQueue offer(Object) 方法不限制,允許長(zhǎng)度變長(zhǎng)
        // 3. PriorityBlockingQueue 插入對(duì)象會(huì)做排序,默認(rèn)參照元素 Comparable 實(shí)現(xiàn),
        //    或者顯示地傳遞 Comparator
        queue.put(9);
        queue.put(1);
        queue.put(8);
        System.out.println("queue.size() =" + queue.size());
        System.out.println("queue.take() =" + queue.take());
        System.out.println("queue =" + queue);
    }
}

運(yùn)行結(jié)果:

queue.size() = 3
queue.take() = 1
queue = [8,9]
7、SYNCHRONOUSQUEUE 請(qǐng)?jiān)u估以下程序的運(yùn)行結(jié)果?
public class SynchronusQueueQuiz{
    
    public static void main(String[] args) throws Exception {
        BlockingQueue queue = new SynchronousQueue<>();
        // 1. SynchronousQueue 是無(wú)空間,offer 永遠(yuǎn)返回 false
        // 2. SynchronousQueue take() 方法會(huì)被阻塞,必須被其他線程顯示地調(diào)用 put(Object);
        System.out.pringln("queue.offer(1) = " + queue.offer(1));
        System.out.pringln("queue.offer(2) = " + queue.offer(2));
        System.out.pringln("queue.offer(3) = " + queue.offer(3));
        System.out.println("queue.take() = " + queue.take());
        System.out.println("queue.size = " + queue.size());
    }
}

運(yùn)行結(jié)果:

queue.offer(1) = false
queue.offer(2) = false
queue.offer(3) = false

SynchronousQueue take() 方法會(huì)被阻塞

8、BLOCKINGQUEUE OFFER() 請(qǐng)?jiān)u估以下程序的運(yùn)行結(jié)果?
public class BlockingQueueQuiz{
    public static void main(String[] args) throws Exception {
        offer(new ArrayBlockingQueue<>(2));
        offer(new LinkedBlockingQueue<>(2));
        offer(new PriorityBlockingQueue<>(2));
        offer(new SynchronousQueue<>());
    }
}

private static void offer(BlockingQueue queue) throws Exception {
    System.out.println("queue.getClass() = " +queue.getClass().getName());
    System.out.println("queue.offer(1) = " + queue.offer(1));
    System.out.println("queue.offer(2) = " + queue.offer(2));
    System.out.println("queue.offer(3) = " + queue.offer(3));
    System.out.println("queue.size() = " + queue.size());
    System.out.println("queue.take() = " + queue.take());
    }
}

運(yùn)行結(jié)果:

queue.getClass() = java.util.concurrent.ArrayBlockingQueue
queue.offer(1) = true
queue.offer(2) = true
queue.offer(3) = false
queue.size() = 2
queue.take() = 1

queue.getClass() = java.util.concurrent.LinkedBlockingQueue
queue.offer(1) = true
queue.offer(2) = true
queue.offer(3) = false
queue.size() = 2
queue.take() = 1

queue.getClass() = java.util.concurrent.PriorityBlockingQueue
queue.offer(1) = true
queue.offer(2) = true
queue.offer(3) = false
queue.size() = 3
queue.take() = 1

queue.getClass() = java.util.concurrent.SynchronousQueue
queue.offer(1) = false
queue.offer(2) = false
queue.offer(3) = false
queue.size() = 0

queue.take() 方法會(huì)被阻塞

Java 并發(fā)框架 1、鎖 LOCK 基本版

請(qǐng)說(shuō)明 ReentranLock 與 ReentrantReadWriteLock 的區(qū)別?

jdk 1.5 以后,ReentranLock(重進(jìn)入鎖)與 ReentrantReadWriteLock 都是可重進(jìn)入的鎖,ReentranLock 都是互斥的,而 ReentrantReadWriteLock 是共享的,其中里面有兩個(gè)類,一個(gè)是 ReadLock(共享,并行,強(qiáng)調(diào)數(shù)據(jù)一致性或者說(shuō)可見(jiàn)性),另一個(gè)是 WriteLock(互斥,串行)。

進(jìn)階版

請(qǐng)解釋 ReentrantLock 為什么命名為重進(jìn)入?

public class ReentrantLockQuestion {

    /**
     * T1 , T2 , T3
     *
     * T1(lock) , T2(park), T3(park)
     * Waited Queue -> Head-> T2 next -> T3
     * T1(unlock) -> unpark all
     * Waited Queue -> Head-> T2 next -> T3
     * T2(free), T3(free)
     *
     * -> T2(lock) , T3(park)
     * Waited Queue -> Head-> T3
     * T2(unlock) -> unpark all
     * T3(free)
     */


    private static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) {
        // thread[main] ->
        // lock     lock           lock
        // main -> action1() -> action2() -> action3()
        synchronizedAction(ReentrantLockQuestion::action1);
    }


    private static void action1() {
        synchronizedAction(ReentrantLockQuestion::action2);

    }

    private static void action2() {
        synchronizedAction(ReentrantLockQuestion::action3);
    }

    private static void action3() {
        System.out.println("Hello,World");
    }

    private static void synchronizedAction(Runnable runnable) {
        lock.lock();
        try {
            runnable.run();
        } finally {
            lock.unlock();
        }
    }
}
勸退版

請(qǐng)說(shuō)明 Lock#lock() 與 Lock#lockInterruptibly() 的區(qū)別?

    /**
     * java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued
     * 如果當(dāng)前線程已被其他線程調(diào)用了 interrupt() 方法時(shí),這時(shí)會(huì)返回 true
     * acquireQueued 執(zhí)行完時(shí),interrupt 清空(false)
     * 再通過(guò) selfInterrupt() 方法將狀態(tài)恢復(fù)(interrupt=true)
     */
         public static void main(String[] args) {
         lockVsLockInterruptibly();
     }
     
        private static void lockVsLockInterruptibly() {

        try {
            lock.lockInterruptibly();
            action1();
        } catch (InterruptedException e) {
            // 顯示地恢復(fù)中斷狀態(tài)
            Thread.currentThread().interrupt();
            // 當(dāng)前線程并未消亡,線程池可能還在存活
        } finally {
            lock.unlock();
        }
    }

lock() 優(yōu)先考慮獲取鎖,待獲取鎖成功后,才響應(yīng)中斷。

lockInterruptibly() 優(yōu)先考慮響應(yīng)中斷,而不是響應(yīng)鎖的普通獲取或重入獲取。

ReentrantLock.lockInterruptibly 允許在等待時(shí)由其它線程調(diào)用等待線程的 Thread.interrupt 方法來(lái)中斷等待線程的等待而直接返回,這時(shí)不用獲取鎖,而會(huì)拋出一個(gè) InterruptedException。

ReentrantLock.lock 方法不允許 Thread.interrupt 中斷,即使檢測(cè)到 Thread.isInterrupted ,一樣會(huì)繼續(xù)嘗試獲取鎖,失敗則繼續(xù)休眠。只是在最后獲取鎖成功后再把當(dāng)前線程置為 interrupted 狀態(tài),然后再中斷線程。

2、條件變量 CONDITION 基本版

請(qǐng)舉例說(shuō)明 Condition 使用場(chǎng)景?

CoutDownLatch (condition 變種)

CyclicBarrier (循環(huán)屏障)

信號(hào)量/燈(Semaphore) java 9

生產(chǎn)者和消費(fèi)者

阻塞隊(duì)列

進(jìn)階版

請(qǐng)使用 Condition 實(shí)現(xiàn) “生產(chǎn)者-消費(fèi)者問(wèn)題”?

使用Condition實(shí)現(xiàn)生產(chǎn)者消費(fèi)者

勸退版

請(qǐng)解釋 Condition await() 和 signal() 與 Object wait () 和 notify() 的相同與差異?

相同:阻塞和釋放

差異:Java Thread 對(duì)象和實(shí)際 JVM 執(zhí)行的 OS Thread 不是相同對(duì)象,JVM Thread 回調(diào) Java Thread.run() 方法,同時(shí) Thread 提供一些 native 方法來(lái)獲取 JVM Thread 狀態(tài),當(dāng)JVM thread 執(zhí)行后,自動(dòng) notify()了。

        while (thread.isAlive()) { // Thread 特殊的 Object
            // 當(dāng)線程 Thread isAlive() == false 時(shí),thread.wait() 操作會(huì)被自動(dòng)釋放
            synchronized (thread) {
                try {
                    thread.wait(); // 到底是誰(shuí)通知 Thread -> thread.notify();
//                    LockSupport.park(); // 死鎖發(fā)生
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
3、屏障 BARRIERS 基本版

請(qǐng)說(shuō)明 CountDownLatch 與 CyclicBarrier 的區(qū)別?

CountDownLatch : 不可循環(huán)的,一次性操作(倒計(jì)時(shí))。

public class CountDownLatchQuestion {

    public static void main(String[] args) throws InterruptedException {

        // 倒數(shù)計(jì)數(shù) 5
        CountDownLatch latch = new CountDownLatch(5);

        ExecutorService executorService = Executors.newFixedThreadPool(5);

        for (int i = 0; i < 4; i++) {
            executorService.submit(() -> {
                action();
                latch.countDown(); // -1
            });
        }

        // 等待完成
        // 當(dāng)計(jì)數(shù) > 0,會(huì)被阻塞
        latch.await();

        System.out.println("Done");

        // 關(guān)閉線程池
        executorService.shutdown();
    }

    private static void action() {
        System.out.printf("線程[%s] 正在執(zhí)行...
", Thread.currentThread().getName());  // 2
    }

}

CyclicBarrier:可循環(huán)的, 先計(jì)數(shù) -1,再判斷當(dāng)計(jì)數(shù) > 0 時(shí)候,才阻塞。

public class CyclicBarrierQuestion {

    public static void main(String[] args) throws InterruptedException {

        CyclicBarrier barrier = new CyclicBarrier(5); // 5

        ExecutorService executorService = Executors.newFixedThreadPool(5); // 3

        for (int i = 0; i < 20; i++) {
            executorService.submit(() -> {
                action();
                try {
                    // CyclicBarrier.await() = CountDownLatch.countDown() + await()
                    // 先計(jì)數(shù) -1,再判斷當(dāng)計(jì)數(shù) > 0 時(shí)候,才阻塞
                    barrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            });
        }

        // 盡可能不要執(zhí)行完成再 reset
        // 先等待 3 ms
        executorService.awaitTermination(3, TimeUnit.MILLISECONDS);
        // 再執(zhí)行 CyclicBarrier reset
        // reset 方法是一個(gè)廢操作
        barrier.reset();

        System.out.println("Done");

        // 關(guān)閉線程池
        executorService.shutdown();
    }

    private static void action() {
        System.out.printf("線程[%s] 正在執(zhí)行...
", Thread.currentThread().getName());  // 2
    }

}
進(jìn)階版

請(qǐng)說(shuō)明 Semaphore(信號(hào)量/燈) 的使用場(chǎng)景?

Semaphore 和Lock類似,比Lock靈活。其中有 acquire() 和 release() 兩種方法,arg 都等于 1。acquire() 會(huì)拋出 InterruptedException,同時(shí)從 sync.acquireSharedInterruptibly(arg:1)可以看出是讀模式(shared); release()中可以計(jì)數(shù),可以控制數(shù)量,permits可以傳遞N個(gè)數(shù)量。

Java中Semaphore(信號(hào)量)的使用

勸退版

請(qǐng)通過(guò) Java 1.4 的語(yǔ)法實(shí)現(xiàn)一個(gè) CountDownLatch?

public class LegacyCountDownLatchDemo {

    public static void main(String[] args) throws InterruptedException {

        // 倒數(shù)計(jì)數(shù) 5
        MyCountDownLatch latch = new MyCountDownLatch(5);

        ExecutorService executorService = Executors.newFixedThreadPool(5);

        for (int i = 0; i < 5; i++) {
            executorService.submit(() -> {
                action();
                latch.countDown(); // -1
            });
        }

        // 等待完成
        // 當(dāng)計(jì)數(shù) > 0,會(huì)被阻塞
        latch.await();

        System.out.println("Done");

        // 關(guān)閉線程池
        executorService.shutdown();
    }

    private static void action() {
        System.out.printf("線程[%s] 正在執(zhí)行...
", Thread.currentThread().getName());  // 2
    }

    /**
     * Java 1.5+ Lock 實(shí)現(xiàn)
     */
    private static class MyCountDownLatch {

        private int count;

        private final Lock lock = new ReentrantLock();

        private final Condition condition = lock.newCondition();

        private MyCountDownLatch(int count) {
            this.count = count;
        }

        public void await() throws InterruptedException {
            // 當(dāng) count > 0 等待
            if (Thread.interrupted()) {
                throw new InterruptedException();
            }

            lock.lock();
            try {
                while (count > 0) {
                    condition.await(); // 阻塞當(dāng)前線程
                }
            } finally {
                lock.unlock();
            }
        }

        public void countDown() {

            lock.lock();
            try {
                if (count < 1) {
                    return;
                }
                count--;
                if (count < 1) { // 當(dāng)數(shù)量減少至0時(shí),喚起被阻塞的線程
                    condition.signalAll();
                }
            } finally {
                lock.unlock();
            }
        }
    }

    /**
     * Java < 1.5 實(shí)現(xiàn)
     */
    private static class LegacyCountDownLatch {

        private int count;

        private LegacyCountDownLatch(int count) {
            this.count = count;
        }

        public void await() throws InterruptedException {
            // 當(dāng) count > 0 等待
            if (Thread.interrupted()) {
                throw new InterruptedException();
            }

            synchronized (this) {
                while (count > 0) {
                    wait(); // 阻塞當(dāng)前線程
                }
            }
        }

        public void countDown() {
            synchronized (this) {
                if (count < 1) {
                    return;
                }
                count--;
                if (count < 1) { // 當(dāng)數(shù)量減少至0時(shí),喚起被阻塞的線程
                    notifyAll();
                }
            }
        }
    }
}
4、線程池 THREAD POOL 基本版

請(qǐng)問(wèn) J.U.C 中內(nèi)建了幾種 ExceptionService 實(shí)現(xiàn)?

1.5:ThreadPoolExecutor、ScheduledThreadPoolExecutor

1.7:ForkJoinPool

public class ExecutorServiceQuestion {

    public static void main(String[] args) {
        /**
         * 1.5
         *  ThreadPoolExecutor
         *  ScheduledThreadPoolExecutor :: ThreadPoolExecutor
         * 1.7
         *  ForkJoinPool
         */
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        executorService = Executors.newScheduledThreadPool(2);

        // executorService 不再被引用,它會(huì)被 GC -> finalize() -> shutdown()
        ExecutorService executorService2 = Executors.newSingleThreadExecutor();
    }
}
進(jìn)階版

請(qǐng)分別解釋 ThreadPoolExecutor 構(gòu)造器參數(shù)在運(yùn)行時(shí)的作用?

/**
 * Creates a new {@code ThreadPoolExecutor} with the given initial
 * parameters.
 *
 * @param corePoolSize the number of threads to keep in the pool, even
 *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
 * @param maximumPoolSize the maximum number of threads to allow in the
 *        pool
 * @param keepAliveTime when the number of threads is greater than
 *        the core, this is the maximum time that excess idle threads
 *        will wait for new tasks before terminating.
 * @param unit the time unit for the {@code keepAliveTime} argument
 * @param workQueue the queue to use for holding tasks before they are
 *        executed.  This queue will hold only the {@code Runnable}
 *        tasks submitted by the {@code execute} method.
 * @param threadFactory the factory to use when the executor
 *        creates a new thread
 * @param handler the handler to use when execution is blocked
 *        because the thread bounds and queue capacities are reached
 * @throws IllegalArgumentException if one of the following holds:
* {@code corePoolSize < 0}
* {@code keepAliveTime < 0}
* {@code maximumPoolSize <= 0}
* {@code maximumPoolSize < corePoolSize} * @throws NullPointerException if {@code workQueue} * or {@code threadFactory} or {@code handler} is null */ public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler);

corePoolSize: 核心線程池大小。這個(gè)參數(shù)是否生效取決于allowCoreThreadTimeOut變量的值,該變量默認(rèn)是false,即對(duì)于核心線程沒(méi)有超時(shí)限制,所以這種情況下,corePoolSize參數(shù)是起效的。如果allowCoreThreadTimeOut為true,那么核心線程允許超時(shí),并且超時(shí)時(shí)間就是keepAliveTime參數(shù)和unit共同決定的值,這種情況下,如果線程池長(zhǎng)時(shí)間空閑的話最終存活的線程會(huì)變?yōu)?,也即corePoolSize參數(shù)失效。

maximumPoolSize: 線程池中最大的存活線程數(shù)。這個(gè)參數(shù)比較好理解,對(duì)于超出corePoolSize部分的線程,無(wú)論allowCoreThreadTimeOut變量的值是true還是false,都會(huì)超時(shí),超時(shí)時(shí)間由keepAliveTime和unit兩個(gè)參數(shù)算出。

keepAliveTime: 超時(shí)時(shí)間。

unit: 超時(shí)時(shí)間的單位,秒,毫秒,微秒,納秒等,與keepAliveTime參數(shù)共同決定超時(shí)時(shí)間。

workQueue: 線程等待隊(duì)列。當(dāng)調(diào)用execute方法時(shí),如果線程池中沒(méi)有空閑的可用線程,那么就會(huì)把這個(gè)Runnable對(duì)象放到該隊(duì)列中。這個(gè)參數(shù)必須是一個(gè)實(shí)現(xiàn)BlockingQueue接口的阻塞隊(duì)列,因?yàn)橐WC線程安全。有一個(gè)要注意的點(diǎn)是,只有在調(diào)用execute方法是,才會(huì)向這個(gè)隊(duì)列中添加任務(wù),那么對(duì)于submit方法呢,難道submit方法提交任務(wù)時(shí)如果沒(méi)有可用的線程就直接扔掉嗎?當(dāng)然不是,看一下AbstractExecutorService類中submit方法實(shí)現(xiàn),其實(shí)submit方法只是把傳進(jìn)來(lái)的Runnable對(duì)象或Callable對(duì)象包裝成一個(gè)新的Runnable對(duì)象,然后調(diào)用execute方法,并將包裝后的FutureTask對(duì)象作為一個(gè)Future引用返回給調(diào)用者。Future的阻塞特性實(shí)際是在FutureTask中實(shí)現(xiàn)的,具體怎么實(shí)現(xiàn)感興趣的話可以看一下FutureTask的源碼。

threadFactory: 線程創(chuàng)建工廠。用于在需要的時(shí)候生成新的線程。默認(rèn)實(shí)現(xiàn)是Executors.defaultThreadFactory(),即new 一個(gè)Thread對(duì)象,并設(shè)置線程名稱,daemon等屬性。

handler: 拒絕策略。這個(gè)參數(shù)的作用是當(dāng)提交任務(wù)時(shí)既沒(méi)有空閑線程,任務(wù)隊(duì)列也滿了,這時(shí)候就會(huì)調(diào)用handler的rejectedExecution方法。默認(rèn)的實(shí)現(xiàn)是拋出一個(gè)RejectedExecutionException異常。

勸退版

如何獲取 ThreadPoolExecutor 正在運(yùn)行的線程?

public class ThreadPoolExecutorThreadQuestion {

    public static void main(String[] args) throws InterruptedException {

        // main 線程啟動(dòng)子線程,子線程的創(chuàng)造來(lái)自于 Executors.defaultThreadFactory()

        ExecutorService executorService = Executors.newCachedThreadPool();
        // 之前了解 ThreadPoolExecutor beforeExecute 和 afterExecute 能夠獲取當(dāng)前線程數(shù)量

        Set threadsContainer = new HashSet<>();

        setThreadFactory(executorService, threadsContainer);
        for (int i = 0; i < 9; i++) { // 開(kāi)啟 9 個(gè)線程
            executorService.submit(() -> {
            });
        }

        // 線程池等待執(zhí)行 3 ms
        executorService.awaitTermination(3, TimeUnit.MILLISECONDS);

        threadsContainer.stream()
                .filter(Thread::isAlive)
                .forEach(thread -> {
                    System.out.println("線程池創(chuàng)造的線程 : " + thread);
                });

        Thread mainThread = Thread.currentThread();

        ThreadGroup mainThreadGroup = mainThread.getThreadGroup();

        int count = mainThreadGroup.activeCount();
        Thread[] threads = new Thread[count];
        mainThreadGroup.enumerate(threads, true);

        Stream.of(threads)
                .filter(Thread::isAlive)
                .forEach(thread -> {
                    System.out.println("線程 : " + thread);
                });

        // 關(guān)閉線程池
        executorService.shutdown();

    }

    private static void setThreadFactory(ExecutorService executorService, Set threadsContainer) {

        if (executorService instanceof ThreadPoolExecutor) {
            ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService;
            ThreadFactory oldThreadFactory = threadPoolExecutor.getThreadFactory();
            threadPoolExecutor.setThreadFactory(new DelegatingThreadFactory(oldThreadFactory, threadsContainer));
        }
    }

    private static class DelegatingThreadFactory implements ThreadFactory {

        private final ThreadFactory delegate;

        private final Set threadsContainer;

        private DelegatingThreadFactory(ThreadFactory delegate, Set threadsContainer) {
            this.delegate = delegate;
            this.threadsContainer = threadsContainer;
        }

        @Override
        public Thread newThread(Runnable r) {
            Thread thread = delegate.newThread(r);
            // cache thread
            threadsContainer.add(thread);
            return thread;
        }
    }
}
5、FUTURE 基本版

如何獲取 Future 對(duì)象?

submit()

進(jìn)階版

請(qǐng)舉例 Future get() 以及 get(Long,TimeUnit) 方法的使用場(chǎng)景?

超時(shí)等待

InterruptedException

ExcutionException

TimeOutException

勸退版

如何利用 Future 優(yōu)雅地取消一個(gè)任務(wù)的執(zhí)行?

public class CancellableFutureQuestion {

    public static void main(String[] args) {

        ExecutorService executorService = Executors.newSingleThreadExecutor();

        Future future = executorService.submit(() -> { // 3秒內(nèi)執(zhí)行完成,才算正常
            action(5);
        });

        try {
            future.get(3, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            // Thread 恢復(fù)中斷狀態(tài)
            Thread.currentThread().interrupt();
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        } catch (TimeoutException e) {
            // 執(zhí)行超時(shí),適當(dāng)?shù)仃P(guān)閉
            Thread.currentThread().interrupt(); // 設(shè)置中斷狀態(tài)
            future.cancel(true); // 嘗試取消
        }

        executorService.shutdown();
    }

    private static void action(int seconds) {
        try {
            Thread.sleep(TimeUnit.SECONDS.toMillis(seconds)); // 5 - 3
            // seconds - timeout = 剩余執(zhí)行時(shí)間
            if (Thread.interrupted()) { // 判斷并且清除中斷狀態(tài)
                return;
            }
            action();
        } catch (InterruptedException e) {
        }
    }

    private static void action() {
        System.out.printf("線程[%s] 正在執(zhí)行...
", Thread.currentThread().getName());  // 2
    }
}
6、VOLATILE 變量 基本版

在 Java 中,volatile 保證的是可見(jiàn)性還是原子性?

volatile 既有可見(jiàn)性又有原子性(非我及彼),可見(jiàn)性是一定的,原子性是看情況的。對(duì)象類型和原生類型都是可見(jiàn)性,原生類型是原子性。

進(jìn)階版

在 Java 中,volatile long 和 double 是線程安全的嗎?

volatile long 和 double 是線程安全的。

勸退版

在 Java 中,volatile 底層實(shí)現(xiàn)是基于什么機(jī)制?

內(nèi)存屏障(變量 Lock)機(jī)制:一個(gè)變量的原子性的保證。

7、原子操作 ATOMIC 基本版

為什么 AtomicBoolean 內(nèi)部變量使用 int 實(shí)現(xiàn),而非 boolean?

操作系統(tǒng)有 X86 和 X64,在虛擬機(jī)中,基于boolean 實(shí)現(xiàn)就是用 int 實(shí)現(xiàn)的,用哪一種實(shí)現(xiàn)都可以。虛擬機(jī)只有32位和64位的,所以用32位的實(shí)現(xiàn)。

進(jìn)階版

在變量原子操作時(shí),Atomic* CAS 操作比 synchronized 關(guān)鍵字哪個(gè)更重?

Synchronization

同線程的時(shí)候,synchronized 剛快;而多線程的時(shí)候則要分情況討論。

public class AtomicQuestion {

    private static int actualValue = 3;

    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(3);
        // if( value == 3 )
        //     value = 5
        atomicInteger.compareAndSet(3, 5);
        // 偏向鎖 < CAS 操作 < 重鎖(完全互斥)
        // CAS 操作也是相對(duì)重的操作,它也是實(shí)現(xiàn) synchronized 瘦鎖(thin lock)的關(guān)鍵
        // 偏向鎖就是避免 CAS(Compare And Set/Swap)操作
    }

    private synchronized static void compareAndSet(int expectedValue, int newValue) {
        if (actualValue == expectedValue) {
            actualValue = newValue;
        }
    }
}
勸退版

Atomic* CAS 的底層是如何實(shí)現(xiàn)?

匯編指令:cpmxchg (Compare and Exchange)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/77891.html

相關(guān)文章

  • 小馬Java項(xiàng)目實(shí)戰(zhàn)訓(xùn)練營(yíng) 極客大學(xué)

    摘要:百度網(wǎng)盤提取碼一面試題熟練掌握是很關(guān)鍵的,大公司不僅僅要求你會(huì)使用幾個(gè),更多的是要你熟悉源碼實(shí)現(xiàn)原理,甚至要你知道有哪些不足,怎么改進(jìn),還有一些有關(guān)的一些算法,設(shè)計(jì)模式等等。 ??百度網(wǎng)盤??提取碼:u6C4?一、java面試題熟練掌握java是很關(guān)鍵的,大公司不僅僅要求你會(huì)使用幾個(gè)api,更多的是要你熟悉源碼實(shí)現(xiàn)原理,甚...

    不知名網(wǎng)友 評(píng)論0 收藏0
  • 小馬Java項(xiàng)目實(shí)戰(zhàn)訓(xùn)練營(yíng) 極客大學(xué)

    摘要:根據(jù)公司的調(diào)查,計(jì)算機(jī)科學(xué)專業(yè)在所有專業(yè)的前五年職業(yè)生涯的基礎(chǔ)薪資中位數(shù)中占據(jù)第一位,約為萬(wàn)美元。市場(chǎng)現(xiàn)狀,產(chǎn)品背景十三五規(guī)劃對(duì)應(yīng)年,大方向是加快壯大戰(zhàn)略性新興產(chǎn)業(yè),打造經(jīng)濟(jì)社會(huì)發(fā)展新引擎。 極客時(shí)間是極客邦科技出品的IT類知識(shí)服務(wù)產(chǎn)品,內(nèi)容包含專欄訂閱、極客新聞、熱點(diǎn)專題、直播、視頻和音頻等多種形式的知識(shí)服務(wù)。極客時(shí)間服...

    codeGoogle 評(píng)論0 收藏0
  • 小馬Java項(xiàng)目實(shí)戰(zhàn)訓(xùn)練營(yíng) 極客大學(xué)

    摘要:根據(jù)公司的調(diào)查,計(jì)算機(jī)科學(xué)專業(yè)在所有專業(yè)的前五年職業(yè)生涯的基礎(chǔ)薪資中位數(shù)中占據(jù)第一位,約為萬(wàn)美元。市場(chǎng)現(xiàn)狀,產(chǎn)品背景十三五規(guī)劃對(duì)應(yīng)年,大方向是加快壯大戰(zhàn)略性新興產(chǎn)業(yè),打造經(jīng)濟(jì)社會(huì)發(fā)展新引擎。 ??????百????度網(wǎng)盤??提取碼:u6C4?極客時(shí)間是極客邦科技出品的IT類知識(shí)服務(wù)產(chǎn)品,內(nèi)容包含專欄訂閱、極客新聞、熱點(diǎn)專題...

    jcc 評(píng)論0 收藏0
  • Java編程方法論:響應(yīng)式RxJava與代碼設(shè)計(jì)實(shí)戰(zhàn)》序

    摘要:原文鏈接編程方法論響應(yīng)式與代碼設(shè)計(jì)實(shí)戰(zhàn)序,來(lái)自于微信公眾號(hào)次靈均閣正文內(nèi)容在一月的架構(gòu)和設(shè)計(jì)趨勢(shì)報(bào)告中,響應(yīng)式編程和函數(shù)式仍舊編列在第一季度的早期采納者中。 原文鏈接:《Java編程方法論:響應(yīng)式RxJava與代碼設(shè)計(jì)實(shí)戰(zhàn)》序,來(lái)自于微信公眾號(hào):次靈均閣 正文內(nèi)容 在《2019 一月的InfoQ 架構(gòu)和設(shè)計(jì)趨勢(shì)報(bào)告》1中,響應(yīng)式編程(Reactive Programming)和函數(shù)式...

    PAMPANG 評(píng)論0 收藏0
  • 前端開(kāi)發(fā)-從入門到Offer - 收藏集 - 掘金

    摘要:一些知識(shí)點(diǎn)有哪些方法方法前端從入門菜鳥(niǎo)到實(shí)踐老司機(jī)所需要的資料與指南合集前端掘金前端從入門菜鳥(niǎo)到實(shí)踐老司機(jī)所需要的資料與指南合集歸屬于筆者的前端入門與最佳實(shí)踐。 工欲善其事必先利其器-前端實(shí)習(xí)簡(jiǎn)歷篇 - 掘金 有幸認(rèn)識(shí)很多在大廠工作的學(xué)長(zhǎng),在春招正式開(kāi)始前為我提供很多內(nèi)部推薦的機(jī)會(huì),非常感謝他們對(duì)我的幫助?,F(xiàn)在就要去北京了,對(duì)第一份正式的實(shí)習(xí)工作也充滿期待,也希望把自己遇到的一些問(wèn)題和...

    sf_wangchong 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<