面试题一
写一个固定容量同步容器,拥有 put 和 get 方法,以及 getCount 方法,能够支持 2 个生成者线程和 10 个消费者线程的阻塞调用。
wait、notify/notifyAll 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 public class MyContainer1 <T> { final private LinkedList <T> lists = new LinkedList <>(); final private int MAX = 10 ; private int count = 0 ; public synchronized void put (T t) { while (lists.size() == MAX) { try { this .wait(); } catch (InterruptedException e) { e.printStackTrace(); } } lists.add(t); ++count; this .notifyAll(); } public synchronized T get () { T t = null ; while (lists.size() == 0 ) { try { this .wait(); } catch (InterruptedException e) { e.printStackTrace(); } } t = lists.removeFirst(); count--; this .notifyAll(); return t; } public static void main (String[] args) { MyContainer1 <String> c = new MyContainer1 <>(); for (int i = 0 ; i < 10 ; i++) { new Thread (() -> { for (int j = 0 ; j < 5 ; j++) { System.out.println(c.get()); } }, "c" + i).start(); } try { TimeUnit.SECONDS.sleep(2 ); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0 ; i < 2 ; i++) { new Thread (() -> { for (int j = 0 ; j < 25 ; j++) { c.put(Thread.currentThread().getName() + " " + j); } }, "p" + i).start(); } } }
Lock、Condition 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 public class MyContainer2 <T> { final private LinkedList <T> lists = new LinkedList <>(); final private int MAX = 10 ; private int count = 0 ; private Lock lock = new ReentrantLock (); private Condition producer = lock.newCondition(); private Condition consumer = lock.newCondition(); public void put (T t) { try { lock.lock(); while (lists.size() == MAX) { producer.await(); } lists.add(t); ++count; consumer.signalAll(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public T get () { T t = null ; try { lock.lock(); while (lists.size() == 0 ) { consumer.await(); } t = lists.removeFirst(); count--; producer.signalAll(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } return t; } public static void main (String[] args) { MyContainer2 <String> c = new MyContainer2 <>(); for (int i = 0 ; i < 10 ; i++) { new Thread (() -> { for (int j = 0 ; j < 5 ; j++) { System.out.println(c.get()); } }, "c" + i).start(); } try { TimeUnit.SECONDS.sleep(2 ); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0 ; i < 2 ; i++) { new Thread (() -> { for (int j = 0 ; j < 25 ; j++) { c.put(Thread.currentThread().getName() + " " + j); } }, "p" + i).start(); } } }
面试题二
实现一个容器,提供两个方法 add、size。写两个线程,线程1 添加 10 个元素到容器中,线程2 实现监控元素的个数,当个数到 5 个时,线程2 给出提示并结束。
volatile 方法
错误写法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public class MyContainer1 { List lists = new ArrayList (); public void add (Object o) { lists.add(o); } public int size () { return lists.size(); } public static void main (String[] args) { MyContainer1 c = new MyContainer1 (); new Thread (() -> { for (int i = 0 ; i < 10 ; i++) { c.add(new Object ()); System.out.println("add " + i); try { TimeUnit.SECONDS.sleep(1 ); } catch (InterruptedException e) { e.printStackTrace(); } } }, "t1" ).start(); new Thread (() -> { while (true ) { if (c.size() == 5 ) { break ; } } System.out.println("t2 结束" ); }, "t2" ).start(); } }
纠正上面写法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public class MyContainer2 { volatile List lists = new ArrayList (); public void add (Object o) { lists.add(o); } public int size () { return lists.size(); } public static void main (String[] args) { MyContainer2 c = new MyContainer2 (); new Thread (() -> { for (int i = 0 ; i < 10 ; i++) { c.add(new Object ()); System.out.println("add " + i); try { TimeUnit.SECONDS.sleep(1 ); } catch (InterruptedException e) { e.printStackTrace(); } } }, "t1" ).start(); new Thread (() -> { while (true ) { if (c.size() == 5 ) { break ; } } System.out.println("t2 结束" ); }, "t2" ).start(); } }
wait、notify方法
错误写法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 public class MyContainer3 { volatile List lists = new ArrayList (); public void add (Object o) { lists.add(o); } public int size () { return lists.size(); } public static void main (String[] args) { MyContainer3 c = new MyContainer3 (); final Object lock = new Object (); new Thread (() -> { synchronized (lock) { System.out.println("t2 启动" ); if (c.size() != 5 ) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("t2 结束" ); } }, "t2" ).start(); try { TimeUnit.SECONDS.sleep(1 ); } catch (InterruptedException e) { e.printStackTrace(); } new Thread (() -> { System.out.println("t1 启动" ); synchronized (lock) { for (int i = 0 ; i < 10 ; i++) { c.add(new Object ()); System.out.println("add " + i); if (c.size() == 5 ) { lock.notify(); } try { TimeUnit.SECONDS.sleep(1 ); } catch (InterruptedException e) { e.printStackTrace(); } } } }, "t1" ).start(); } }
纠正上面的写法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 public class MyContainer4 { volatile List lists = new ArrayList (); public void add (Object o) { lists.add(o); } public int size () { return lists.size(); } public static void main (String[] args) { MyContainer4 c = new MyContainer4 (); final Object lock = new Object (); new Thread (() -> { synchronized (lock) { System.out.println("t2 启动" ); if (c.size() != 5 ) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("t2 结束" ); lock.notify(); } }, "t2" ).start(); try { TimeUnit.SECONDS.sleep(1 ); } catch (InterruptedException e) { e.printStackTrace(); } new Thread (() -> { System.out.println("t1 启动" ); synchronized (lock) { for (int i = 0 ; i < 10 ; i++) { c.add(new Object ()); System.out.println("add " + i); if (c.size() == 5 ) { lock.notify(); try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } try { TimeUnit.SECONDS.sleep(1 ); } catch (InterruptedException e) { e.printStackTrace(); } } } }, "t1" ).start(); } }
CountDownLatch 方法(最优方法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 public class MyContainer5 { volatile List lists = new ArrayList (); public void add (Object o) { lists.add(o); } public int size () { return lists.size(); } public static void main (String[] args) { MyContainer5 c = new MyContainer5 (); CountDownLatch latch = new CountDownLatch (1 ); new Thread (() -> { System.out.println("t2 启动" ); if (c.size() != 5 ) { try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("t2 结束" ); }, "t2" ).start(); try { TimeUnit.SECONDS.sleep(1 ); } catch (InterruptedException e) { e.printStackTrace(); } new Thread (() -> { System.out.println("t1 启动" ); for (int i = 0 ; i < 10 ; i++) { c.add(new Object ()); System.out.println("add " + i); if (c.size() == 5 ) { latch.countDown(); } try { TimeUnit.SECONDS.sleep(1 ); } catch (InterruptedException e) { e.printStackTrace(); } } }, "t1" ).start(); } }
源码:https://github.com/V-Vincen/threads/tree/master/src/main/java/com/example/_exercise
If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !