前面針對多線程相關知識點進行了學習,那麼咱們來來看看常見的面試題:html
1. 空中網面試題1 package com.kongzhongwang.interview; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; //myeclipse強大功能:將代碼直接複製到項目的src路徑下能夠自動相應生成包名和類名 /** * * 空中網面試題1:現有程序代碼模擬產生16個日誌對象,而且須要運行16秒才能打印完這些日誌,請在程序中增長四個線程去調用 * parseLog()方法來分頭打印這16個日誌對象,程序只需運行4秒便可打印完這些日誌對象。 * 考察新技術BlockingQueue */ public class ReadLog { public static void main(String[] args) { /*此處有一個巧合:這裏ArrayBlockingQueue<String>(1)和ArrayBlockingQueue<String>(16) * 達到的效果同樣,而且前者產生的數據組合更整齊;目前推測是巧合,但願大牛發現因果了告知一聲 */ final BlockingQueue<String> queue = new ArrayBlockingQueue<String>(1); for (int i = 0; i < 4; i++) { new Thread(new Runnable() { public void run() { while (true) { try { String log = queue.take(); parseLog(log); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } System.out.println("begin:" + (System.currentTimeMillis() / 1000)); /* * 模擬處理16個日誌,下面代碼產生了16個日誌對象;當前代碼須要運行16秒才能打印完成這些日誌對象; * 修改程序代碼,開四個線程讓16個對象在4秒內打完 */ for (int i = 0; i < 16; i++) { // 這行代碼不能改動 final String log = "" + (i + 1); // 這行代碼不能改動 { // ReadLog.parseLog(log); try { queue.put(log); } catch (InterruptedException e) { e.printStackTrace(); } } } } // parseLog內部代碼不能動 public static void parseLog(String log) { System.out.println(log + ":" + System.currentTimeMillis() / 1000); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } 2. 空中網面試題2 package com.kongzhongwang.interview; import java.util.concurrent.Semaphore; import java.util.concurrent.SynchronousQueue; /** * 空中網面試題2: 現成程序中的Test類中的代碼在不斷地產生數據,而後交給TestDo.doSome()方法去處理; * 這就好像是生產者在不斷地產生數據,消費者在不斷地消費數據。請將程序改形成有10個線程來消費生產者產生的數據, * 這些消費者都調用TestDo.doSome()方法去處理,固每一個消費者都須要1秒才能處理完,程序應該保證這些 * 消費者線程依次有序的消費數據,只有上一個消費者消費完後,下一個消費者才能消費數據,下一個消費者是誰均可以, 但要保證消費者拿到的數據是有順序的。 */ public class Test { public static void main(String[] args) { //使用semaphore信號燈至關於上一個lock鎖 final Semaphore semaphore = new Semaphore(1); //新的隊列方式 final SynchronousQueue<String> queue = new SynchronousQueue<String>(); for(int i=0;i<10;i++){ new Thread(new Runnable() { @Override public void run() { try { semaphore.acquire(); String input = queue.take(); String output = TestDo.doSome(input); System.out.println(Thread.currentThread().getName() + ":" + output); semaphore.release(); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } System.out.println("begin:" + (System.currentTimeMillis() / 1000)); for (int i = 0; i < 10; i++) { // 這行代碼不能改動 String input = i + ""; // 這行代碼不能改動 try { queue.put(input); } catch (InterruptedException e) { e.printStackTrace(); } } } } // TestDo類不能動 class TestDo { public static String doSome(String input) { try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } String output = input + ":" + (System.currentTimeMillis() / 1000); return output; } } 3.空中網面試題3 package com.kongzhongwang.interview; import java.util.ArrayList; import java.util.Iterator; import java.util.concurrent.CopyOnWriteArrayList; public class Tests extends Thread { /** * 空中網面試題3: 現有程序同時啓動了四個線程去調用TestDo.doSome(key,value)方法; * 因爲TestsDo.doSome(key,value)方法內的代碼是先暫停1秒,而後再輸出以秒爲單位的當前時間值, * 因此會打印出四個相同的時間值,以下所示:4:4 1258199615 1:1 1258199615 3:3 1258199615 2:2 * 1258199615 ;請修改代碼,若是有幾個線程調用TestDo.doSome(key,value)方法時; * 傳遞進去的key值相等(equals比較爲true),則這幾個線程應互斥輸出結果,即當有兩個線程的key都爲1時, * 它們中的一個要比其餘線程晚一步輸出結果,以下所示:4:4 1258199615 1:1 1258199615 3:3 1258199615 1:2 * 1258199616 ;總之每一個線程中指定的key相等時;這些相等的線程應每隔1秒輸出時間值(要用互斥), * key不一樣,則並行執行(相互之間不互斥) */ private TestsDo testDo; private String key; private String value; private Tests(String key, String key2, String value) { this.testDo = TestsDo.getInstance(); /* * 常量「1」和「1」是同一個對象,下面這行代碼就是要用「1」+「」的方式產生新的對象; * 以實現內容沒有改變,仍然相等(都還爲「1」),但對象卻再也不是同一個的效果 */ this.key = key + key2; /* * a = "1"+""; * b = "2"+""; * a和b是同一個對象,由於編譯器在執行以前就會將其優化爲 a=「1」; * 可是this.key = key + key2;這句,編譯器不會給你優化, * 由於你是屬性變量,編譯器不知道你未來要傳入什麼值 */ this.value = value; } public static void main(String[] args) { Tests a = new Tests("1", "", "1"); Tests b = new Tests("1", "", "2"); Tests c = new Tests("3", "", "3"); Tests d = new Tests("4", "", "4"); System.out.println("begin:" + (System.currentTimeMillis() / 1000)); a.start(); b.start(); c.start(); d.start(); } public void run() { testDo.doSome(key, value); } } class TestsDo { private TestsDo() {} private static TestsDo _instance = new TestsDo(); public static TestsDo getInstance() { return _instance; } //傳統寫法,沒有考慮到線程併發問題 // private ArrayList keys = new ArrayList(); private CopyOnWriteArrayList keys = new CopyOnWriteArrayList(); public void doSome(Object key,String value){ Object o = key; if(! keys.contains(o)){ keys.add(o); }else{ //迭代的過程當中不能進行其餘操做; for(Iterator iter = keys.iterator();iter.hasNext();){ /*這裏的休眠做用:爲了讓你們看到,使用傳統的private ArrayList keys = new ArrayList(); * 會致使Exception in thread "Thread-1" java.util.ConcurrentModificationException異常 * 由於迭代的過程當中不能進行其餘操做;你非要在迭代的時候向其中添加數據就會致使這種異常,並且在迭代中放入休眠這種錯誤百發百中。 */ try { Thread.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); } Object oo = iter.next(); if(o.equals(oo)){ o = oo; } } } //這裏爲了區別是不一樣對象,因此不能直接使用synchronized(key) synchronized(o) //大括號內的是須要同步的代碼,不能改動 { try{ Thread.sleep(1000); System.out.println(key+":"+value+":" + (System.currentTimeMillis() / 1000)); }catch(Exception e){ e.printStackTrace(); } } } }
其它面試題:java
https://www.cnblogs.com/Jansens520/p/8624708.html面試