最近学了很多线程方面的知识,如果不实践一下很快就会忘了,所以就去找了两道大厂的面试题,今天先做了一道,明天再更一道,哈哈。
题目是这样的:
实现一个容器,提供两个方法,add,size。写两个线程,线程1往容器里添加10个元素,线程2实现监控元素的个数,当个数到5时,线程2给出提示并结束
其实这个题目并不难,首先分析题目,实现一个容器和两个方法,这里我们容器就用list,然后一个写一个读,我们要做到是他在写的过程中可以让读的线程知道写进去几个数据了,那么重点是什么,没错就是数据一致性,这是做这道题的重点,然后就是如何让读线程知道容器里已经添加了5个元素了,这个就要大家来思考一下了。好了闲话少说,直接上代码,我写了四个demo,当然第一个是有问题的,一起来看看吧
几个demo中t1 为添加元素的线程,t2为监控元素数量的线程。这里的容器我都用了同步集合Collections.synchronizedList(new LinkedList<>()),用volatile来修饰 是因为他的可见性。注意,几个demo都要让t2先启动,不然还是会出现问题。
第一个demo中,t2线程里面我写了一个while循环去不停的调用size方法,如果返回5就跳出循环 结束任务,t1线程则是写了个循环添加10个元素,图中我写了注释,是因为会出现t2在读完数据到下次读取数据期间,t1添加了5,并且添加了6或者更多,这时t2读取的数据跳过5,就变成死循环了。所以这个demo不是一个完美的答案。
第二个demo中,这里太长了没有截全,上面的代码和第一个demo是一样的。我在t1,t2里都加了锁,这个是利用了wait和notify,到5的时候让t1去叫醒t2,然后t1 wait ,t2 获取锁继续执行,执行完了之后叫醒t1,t1获取锁再继续执行。这里等于没有再让t2去监控容器,而是让t1去告诉t2我已经添加了5个元素了,这样就不会出现数据不一致的问题了。后面两个demo的思路也是这样的,只是用的类不一样而已
第三个demo中,利用countDownLatch的特性,t2 先执行,然后await。t1每次添加元素的时候countDown一次,5次的时候t2就开始执行了,t1再await,然后等t2执行结束,t2 countDown,t1 继续执行直到结束。
第四个demo中,这里利用了LockSupport可以阻塞线程的特点,t2先执行,然后park阻塞,t1开始添加元素,到5个后,t1 unpark(t2)让t2 继续执行,同时t1 park阻塞,t2执行完之后,t2 unpark(t1)让t1继续执行直到结束。
大家有更好的思路的话可以评论区留言大家一起讨论一下