From aeef89fdc26f664f0a1babb818e18f0c6700e333 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B6=E5=AD=90?= Date: Sat, 4 Jan 2020 16:46:00 +0800 Subject: [PATCH 1/7] add week_04/09/CopyOnWriteArrayList. --- week_04/09/CopyOnWriteArrayList | 1 + 1 file changed, 1 insertion(+) create mode 100644 week_04/09/CopyOnWriteArrayList diff --git a/week_04/09/CopyOnWriteArrayList b/week_04/09/CopyOnWriteArrayList new file mode 100644 index 0000000..488cb27 --- /dev/null +++ b/week_04/09/CopyOnWriteArrayList @@ -0,0 +1 @@ +阅读链接:彤哥读源码之“死磕 java集合之CopyOnWriteArrayList源码分析” \ No newline at end of file -- Gitee From 6d1f9751cfeb808917b814df5d569e36a29ebfee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B6=E5=AD=90?= Date: Sat, 4 Jan 2020 16:52:47 +0800 Subject: [PATCH 2/7] update week_04/09/CopyOnWriteArrayList. --- week_04/09/CopyOnWriteArrayList | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/week_04/09/CopyOnWriteArrayList b/week_04/09/CopyOnWriteArrayList index 488cb27..97cee00 100644 --- a/week_04/09/CopyOnWriteArrayList +++ b/week_04/09/CopyOnWriteArrayList @@ -1 +1,7 @@ -阅读链接:彤哥读源码之“死磕 java集合之CopyOnWriteArrayList源码分析” \ No newline at end of file +阅读参考链接:彤哥读源码之“死磕 java集合之CopyOnWriteArrayList源码分析” + +总结: +1)CopyOnWrite 即 写入时复制; +2)CopyOnWriteArrayList是ArrayList的线程安全版本,内部也是通过数组实现,每次对数组的修改都完全拷贝一份新的数组来修改,修改完了再替换掉老数组, +这样保证了只阻塞写操作,不阻塞读操作,实现读写分离。 +3)虽然线程安全,但是如果旧数组是对象比较大的,频繁地进行替换会消耗内存,非常消耗性能,从而引发Java的GC问题。 -- Gitee From e6979d0d56fd7ba4d0d4e46adbbc27a9db28282a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B6=E5=AD=90?= Date: Sat, 4 Jan 2020 22:02:12 +0800 Subject: [PATCH 3/7] add week_04/09/ConcurrentHashMap. --- week_04/09/ConcurrentHashMap | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 week_04/09/ConcurrentHashMap diff --git a/week_04/09/ConcurrentHashMap b/week_04/09/ConcurrentHashMap new file mode 100644 index 0000000..a2bbfd9 --- /dev/null +++ b/week_04/09/ConcurrentHashMap @@ -0,0 +1,22 @@ + +学习链接: +https://www.cnblogs.com/williamjie/p/9099861.html(jdk6/7&jdk8之间的区别,着重理解最常用的put()/ get()) +学习公众号: +彤哥读源码(详细分析了ConcurrentHashMap 源码) + +总结: +1、理解ConcurrentHashMap + Concurrent翻译过来是并发的意思,字面理解它的作用是处理并发情况的 HashMap;多线程并发下 HashMap 是不安全的(如死循环), + 更普遍的是多线程并发,内部也是使用(数组 + 链表 + 红黑树)的结构来存储元素。 +2、ConcurrentHashMap使用了哪些锁 + JDK6与JDK7中实现分段锁,只有在同一个分段内才存在竞态关系,不同的分段锁之间没有锁竞争;ConcurrentHashMap中的分段锁称为Segment,它即类似于HashMap + 结构,即内部拥有一个Entry数组,数组中的每个元素又是一个链表;同时又是一个ReentrantLock(Segment继承了ReentrantLock)。ConcurrentHashMap中的HashEntry相对于HashMap中的Entry有一定的差异性: + HashEntry中的value以及next都被volatile修饰,这样在多线程读写过程中能够保持它们的可见性; + JDK8中进行了巨大改动,利用CAS算法,它沿用了与它同时期的HashMap版本的思想,底层依然由“数组”+链表+红黑树的方式思想(JDK7与JDK8中HashMap的实现),但是为了做到并发,又增加了很多辅助的类, + 例如TreeBin,Traverser等对象内部类。 +3、ConcurrentHashMap看起来比较吃力,我觉得还需要慢慢研读和理解。 + + + + + -- Gitee From a0ef74f299893e87c18722fdc66ddac2ba563e9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B6=E5=AD=90?= Date: Sun, 5 Jan 2020 09:45:49 +0800 Subject: [PATCH 4/7] add week_04/09/ArrayBlockingQueue. --- week_04/09/ArrayBlockingQueue | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 week_04/09/ArrayBlockingQueue diff --git a/week_04/09/ArrayBlockingQueue b/week_04/09/ArrayBlockingQueue new file mode 100644 index 0000000..fe7e877 --- /dev/null +++ b/week_04/09/ArrayBlockingQueue @@ -0,0 +1,8 @@ +学习链接:https://www.cnblogs.com/kexianting/p/8550598.html +总结: +1)在实际应用中,linkBlockingQueue使用更广泛(是一个链表),ArrayBlockingQueue一个由数组支持的有界阻塞队列,按FIFO对元素进行排序,(队列的头部 是在队列中存在时间最长的元素。队列的尾部 是在队列中存在时间最短的元素。新元素插入到队列的尾部, +队列检索操作则是从队列头部开始获得元素) +2)实现采用一个共享锁final ReentrantLock lock ; +3)对队列enqueue()/dequeue()(入队/出队)理解,以及关于offer()方法; +4)总体比较好接受。 + -- Gitee From b8f9262595cffe09d92de06287474ef5acc2aa45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B6=E5=AD=90?= Date: Sun, 5 Jan 2020 11:52:07 +0800 Subject: [PATCH 5/7] add week_04/09/ConcurrentLinkedQueue. --- week_04/09/ConcurrentLinkedQueue | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 week_04/09/ConcurrentLinkedQueue diff --git a/week_04/09/ConcurrentLinkedQueue b/week_04/09/ConcurrentLinkedQueue new file mode 100644 index 0000000..f41498b --- /dev/null +++ b/week_04/09/ConcurrentLinkedQueue @@ -0,0 +1,13 @@ +学习参考链接: +https://blog.csdn.net/qq_38293564/article/details/80798310(详细介绍,有源代码分析) +https://www.cnblogs.com/yangzhenlong/p/8359875.html(这个文章格式看起来比较舒服规范,对应的方法有demo,使用学习比较快) + +总结: +ConcurrentLinkedQueue 的非阻塞算法实现可概括为下面 5 点: + +1)使用 CAS 原子指令来处理对数据的并发访问,这是非阻塞算法得以实现的基础。 +2)head/tail 并非总是指向队列的头 / 尾节点,也就是说允许队列处于不一致状态。 这个特性把入队 / 出队时,原本需要一起原子化执行的两个步骤分离开来, +从而缩小了入队 / 出队时需要原子化更新值的范围到唯一变量。这是非阻塞算法得以实现的关键。 +3)由于队列有时会处于不一致状态。为此,ConcurrentLinkedQueue 使用三个不变式来维护非阻塞算法的正确性。 +4)以批处理方式来更新 head/tail,从整体上减少入队 / 出队操作的开销。 +5)为了有利于垃圾收集,队列使用特有的 head 更新机制;为了确保从已删除节点向后遍历,可到达所有的非删除节点,队列使用了特有的向后推进策略。 -- Gitee From 0274d527c51e70e2d4cd0d604f4b0e33cd5d60fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B6=E5=AD=90?= Date: Sun, 5 Jan 2020 15:42:49 +0800 Subject: [PATCH 6/7] add week_04/DelayQueue. --- week_04/DelayQueue | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 week_04/DelayQueue diff --git a/week_04/DelayQueue b/week_04/DelayQueue new file mode 100644 index 0000000..ea9c10d --- /dev/null +++ b/week_04/DelayQueue @@ -0,0 +1,13 @@ +1、总结: + DelayQueue是java并发包下的延时阻塞队列,常用于实现定时任务。 + + 内部存储结构使用优先级队列PriorityQueue q = new PriorityQueue(); + + 入队方法,add(E e)/put(E e) /offer(E e, long timeout, TimeUnit unit)/ ,实现均为offer(E e) + 因为DelayQueue是阻塞队列,且优先级队列是无界的,所以入队不会阻塞不会超时; + + 出队方法,poll()/take() + + demo参考 死磕 java集合之DelayQueue源码分析 + +2、学习参考“彤哥读源码”公众号 -- Gitee From f11281b877ac854fbda206ef34e1c8883a0d8f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B6=E5=AD=90?= Date: Mon, 6 Jan 2020 17:17:49 +0800 Subject: [PATCH 7/7] =?UTF-8?q?leetcode-=E4=BA=A4=E6=9B=BF=E6=89=93?= =?UTF-8?q?=E5=8D=B0foobar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\233\277\346\211\223\345\215\260foobar.md" | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 "week_05/09/Leetcode-\344\272\244\346\233\277\346\211\223\345\215\260foobar.md" diff --git "a/week_05/09/Leetcode-\344\272\244\346\233\277\346\211\223\345\215\260foobar.md" "b/week_05/09/Leetcode-\344\272\244\346\233\277\346\211\223\345\215\260foobar.md" new file mode 100644 index 0000000..c4db1df --- /dev/null +++ "b/week_05/09/Leetcode-\344\272\244\346\233\277\346\211\223\345\215\260foobar.md" @@ -0,0 +1,72 @@ +Leetcode——交替打印foobar + +解法一:利用synchronized + +```java +public class FooBar { + + private int n ; //输出次数 + private boolean isFooBar = true; //是否执行打印 + private Object o = new Object(); //锁对象 + + public FooBar(int n) { + this.n = n; + } + + public void foo(Runnable foo) throws InterruptedException { + for(int i = 0; i < n ; i ++){ + synchronized (o){ + if(!isFooBar){ + o.wait(); + } + foo.run(); + isFooBar = false; + System.out.println("foo"); + o.notify(); + } + + } + } + + public void bar(Runnable bar) throws InterruptedException { + for(int j = 0 ; j < n ;j++){ + synchronized (o){ + if(isFooBar){ + o.wait(); + } + bar.run(); + isFooBar = true; + System.out.println("bar"); + o.notify(); + } + + } + } + public static void main(String[] args) throws InterruptedException { + FooBar fooBar = new FooBar(2); + //创建一个foo线程: + new Thread(){ + public void run(){ + try { + fooBar.foo(new Thread()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }.start(); + //创建一个bar线程 + new Thread(){ + public void run(){ + try { + fooBar.bar(new Thread()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }.start(); + + } +} + +``` + -- Gitee