传统艺能,点到为止


文章目录

  • 并发包
    • 你接触过哪些线程安全类?
    • 你使用过哪些jdk1.5并发包下的类?
  • Vector和ArrayList
    • Vector和ArrayList的区别
    • Vector源码
    • ArrayList源码
  • Hashtable和HashMap
    • Hashtable和HashMap的区别?
    • Hashtable和HashMap的底层实现?
    • Hashtable put方法源码
    • HashMap put方法源码
  • SynchronizedMap
    • 什么是SynchronizedMap?
    • SynchronizedMap原理?
  • ConcurrentHashMap
    • ConcurrentHashMap设计思路/底层?
  • CountDownLatch
    • 什么是CountDownLatch?
    • CountDownLatch例子
  • CyclicBarrier
    • 什么是CyclicBarrier?
    • CyclicBarrier例子
  • Semaphore
    • 什么是Semaphore
    • Semaphore例子
  • 并发队列
    • 并发队列有界和无界的区别?
    • 阻塞与非阻塞队列的区别?
    • 非阻塞式队列ConcurrentLinkedDeque
    • 阻塞式队列BlockingQueue
    • BlockingQueue和ConcurrentLinkedDeque的区别?
    • 生产者消费者例子

并发包

你接触过哪些线程安全类?

你使用过哪些jdk1.5并发包下的类?

Vector和ArrayList

Vector和ArrayList的区别

Vector和ArrayList原理都是由数组实现的,查询速度块,增加、修改和删除速度慢。

最大的区别在于线程安全问题,Vector是线程安全的,ArrayList是线程不安全的,但ArrayList效率更高。

Vector是线程安全的那么必然是上了锁的类集合。

Vector源码

点进Vector类,看get set add方法的实现,我们发现他们的方法都被synchronized所修饰。多个线程使用Vector类,只要有一个线程在操作,其他线程都读不了数据,还引发锁资源竞争,因此效率很低。

 /*** Returns the element at the specified position in this Vector.** @param index index of the element to return* @return object at the specified index* @throws ArrayIndexOutOfBoundsException if the index is out of range*            ({@code index < 0 || index >= size()})* @since 1.2*/public synchronized E get(int index) {if (index >= elementCount)throw new ArrayIndexOutOfBoundsException(index);return elementData(index);}/*** Replaces the element at the specified position in this Vector with the* specified element.** @param index index of the element to replace* @param element element to be stored at the specified position* @return the element previously at the specified position* @throws ArrayIndexOutOfBoundsException if the index is out of range*         ({@code index < 0 || index >= size()})* @since 1.2*/public synchronized E set(int index, E element) {if (index >= elementCount)throw new ArrayIndexOutOfBoundsException(index);E oldValue = elementData(index);elementData[index] = element;return oldValue;}/*** Appends the specified element to the end of this Vector.** @param e element to be appended to this Vector* @return {@code true} (as specified by {@link Collection#add})* @since 1.2*/public synchronized boolean add(E e) {modCount++;ensureCapacityHelper(elementCount + 1);elementData[elementCount++] = e;return true;}

ArrayList源码

点进ArrayList一看就知道,是没有做任何的同步

/*** Returns the element at the specified position in this list.** @param  index index of the element to return* @return the element at the specified position in this list* @throws IndexOutOfBoundsException {@inheritDoc}*/public E get(int index) {rangeCheck(index);return elementData(index);}/*** Replaces the element at the specified position in this list with* the specified element.** @param index index of the element to replace* @param element element to be stored at the specified position* @return the element previously at the specified position* @throws IndexOutOfBoundsException {@inheritDoc}*/public E set(int index, E element) {rangeCheck(index);E oldValue = elementData(index);elementData[index] = element;return oldValue;}/*** Appends the specified element to the end of this list.** @param e element to be appended to this list* @return <tt>true</tt> (as specified by {@link Collection#add})*/public boolean add(E e) {ensureCapacityInternal(size + 1);  // Increments modCount!!elementData[size++] = e;return true;}

Hashtable和HashMap

Hashtable和HashMap的区别?

HashTable线程安全,HashMap线程不安全

Hashtable和HashMap的底层实现?

//todo 以后在细写吧。

链表+数组,链表做增加删除, HashCode取模得到下标位置,一致性取模算法。

Hashtable put方法源码

很明显可以看到put方法加了synchronized关键字。

 public synchronized V put(K key, V value) {// Make sure the value is not nullif (value == null) {throw new NullPointerException();}// Makes sure the key is not already in the hashtable.Entry<?,?> tab[] = table;int hash = key.hashCode();int index = (hash & 0x7FFFFFFF) % tab.length;@SuppressWarnings("unchecked")Entry<K,V> entry = (Entry<K,V>)tab[index];for(; entry != null ; entry = entry.next) {if ((entry.hash == hash) && entry.key.equals(key)) {V old = entry.value;entry.value = value;return old;}}addEntry(hash, key, value, index);return null;}

HashMap put方法源码

没有synchronized关键字

 /** * Associates the specified value with the specified key in this map.* If the map previously contained a mapping for the key, the old* value is replaced.** @param key key with which the specified value is to be associated* @param value value to be associated with the specified key* @return the previous value associated with <tt>key</tt>, or*         <tt>null</tt> if there was no mapping for <tt>key</tt>.*         (A <tt>null</tt> return can also indicate that the map*         previously associated <tt>null</tt> with <tt>key</tt>.)*/public V put(K key, V value) {return putVal(hash(key), key, value, false, true);}/*** Implements Map.put and related methods** @param hash hash for key* @param key the key* @param value the value to put* @param onlyIfAbsent if true, don't change existing value* @param evict if false, the table is in creation mode.* @return previous value, or null if none*/final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {Node<K,V>[] tab; Node<K,V> p; int n, i;if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);else {Node<K,V> e; K k;if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))e = p;else if (p instanceof TreeNode)e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);else {for (int binCount = 0; ; ++binCount) {if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(tab, hash);break;}if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}if (e != null) { // existing mapping for keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e);return oldValue;}}++modCount;if (++size > threshold)resize();afterNodeInsertion(evict);return null;}

SynchronizedMap

什么是SynchronizedMap?

是Collections中的静态类,可以将不安全Map集合转变为安全的集合

//todo Collections再单独拿出来写吧…

SynchronizedMap原理?

原理无非就是用了Object锁的synchronized代码块

 private static class SynchronizedMap<K,V>implements Map<K,V>, Serializable {private static final long serialVersionUID = 1978198479659022715L;private final Map<K,V> m;     // Backing Mapfinal Object      mutex;        // Object on which to synchronizeSynchronizedMap(Map<K,V> m) {this.m = Objects.requireNonNull(m);mutex = this;}SynchronizedMap(Map<K,V> m, Object mutex) {this.m = m;this.mutex = mutex;}public int size() {synchronized (mutex) {return m.size();}}public boolean isEmpty() {synchronized (mutex) {return m.isEmpty();}}public boolean containsKey(Object key) {synchronized (mutex) {return m.containsKey(key);}}public boolean containsValue(Object value) {synchronized (mutex) {return m.containsValue(value);}}public V get(Object key) {synchronized (mutex) {return m.get(key);}}public V put(K key, V value) {synchronized (mutex) {return m.put(key, value);}}public V remove(Object key) {synchronized (mutex) {return m.remove(key);}}public void putAll(Map<? extends K, ? extends V> map) {synchronized (mutex) {m.putAll(map);}}public void clear() {synchronized (mutex) {m.clear();}}//...
}

ConcurrentHashMap

jdk1.5之后产生了许多的java并发包,ConcurrentHashMap就是其中之一,为解决1.2的Hashtable虽然是线程安全的但是效率非常低,造成锁的资源竞争问题。

ConcurrentHashMap设计思路/底层?

分段锁,将一个整体Map拆分成多个小的Hashtable,默认分成16段(上限为16),我们具体的假设,如Map的下标0到4分为一个Hashtable,5-9分为一个Hashtable,10-14分为一个Hashtable…多线程的情况下,线程①查询下标2,线程②查询下标5,线程③查询下标10,那么这三个线程并不使用同一把锁,相比之前的Hashtable,Hashtable三个线程共用同一把锁,ConcurrentHashMap减少了锁的资源竞争,因此效率得到了提高。并且代码中大多共享变量使用volatile关键字声明,目的是第一时间获取修改的内容。volatile不只是起到可见性的作用,还起禁止重排序功能。

CountDownLatch

什么是CountDownLatch?

CountDownLatch类位于concurrent包下,利用它可以实现类似计数器的功能,比如有一个任务A,它要等其他4个任务执行完毕后才能执行,此时就可以使用CountDownLatch来实现这种功能了。相比join可能会更方便一些。

CountDownLatch例子

使用起来很简单,实例化CountDownLatch,给初始值,使用countDown函数计数减一,使用countDownLatch.await()进行阻塞判断,大于0一直阻塞,小于等于0停止阻塞。

代码见下:

import lombok.SneakyThrows;import java.util.concurrent.CountDownLatch;public class CountDown {@SneakyThrowspublic static void main(String[] args) {// 定义计数器CountDownLatch countDownLatch = new CountDownLatch(2);Thread thread1 = new Thread(new Runnable() {@SneakyThrows@Overridepublic void run() {System.out.println("我是子线程1执行任务");Thread.sleep(10);System.out.println("我是子线程1执行任务");// 计数器减一countDownLatch.countDown();}});Thread thread2 = new Thread(new Runnable() {@SneakyThrows@Overridepublic void run() {System.out.println("我是子线程2执行任务");Thread.sleep(10);System.out.println("我是子线程2执行任务");countDownLatch.countDown();}});thread1.start();thread2.start();// 如果不为0,阻塞countDownLatch.await();System.out.println("主线程开始执行任务");for (int i = 0; i < 3; i++) {Thread.sleep(1000);System.out.println(i);}System.out.println("主线程执行任务结束");}
}

CyclicBarrier

什么是CyclicBarrier?

jdk1.5并发包中的类,用的不多,了解即可,也是做计数用的,当我们线程到达一定次数,开始并行执行。

CyclicBarrier例子


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.SneakyThrows;import java.util.concurrent.CyclicBarrier;@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
class MyThread extends Thread {private CyclicBarrier cyclicBarrier;@SneakyThrows@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + ",开始写入任务");// 模拟任务执行时间Thread.sleep(1);// await大于0时线程阻塞和计数减一,当为0的时候,所有线程共同并行cyclicBarrier.await();System.out.println(Thread.currentThread().getName() + ",写入任务结束...");}
}public class CyclicTest {public static void main(String[] args) {CyclicBarrier cyclicBarrier = new CyclicBarrier(50);for (int i = 0; i < 50; i++) {new MyThread(cyclicBarrier).start();}}
}

Semaphore

什么是Semaphore

Semaphore属于并发包中的一类,Semaphore可以看作是一种基于计数的信号量,可以设定一个阈值,这个阈值表示最多支持几个线程访问,基于此,多个线程竞争获取许可信号,做自己的申请后归还,超过阈值后,线程申请许可信号将会被阻塞。

Semaphore可以用来构建一些对象池,资源池,比如数据库连接池,Semaphore计数为1,将变成类似互斥锁的机制。

Semaphore这个概念应该并不陌生。

Semaphore例子

掌握主要方法acquire、availablePermits、release,获取和释放资源
acquire 获取资源,计数-1,阻塞等待
release释放资源计数+1
availablePermits返回此Semaphore对象中当前可用的许可数,许可的数量有可能实时在改变,并不是固定的数量。

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.SneakyThrows;import java.util.Random;
import java.util.concurrent.Semaphore;@Data
@AllArgsConstructor
class Parent implements Runnable {private Semaphore semaphore;private String name;@SneakyThrows@Overridepublic void run() {int i = semaphore.availablePermits();if (i > 0) {System.out.println(getName() +  " ,i > 0");} else {System.out.println(getName() +  " ,i < 0,wait..");}semaphore.acquire();System.out.println(getName() +  " ,entering...");Thread.sleep(new Random().nextInt(10000));System.out.println(getName() +   " ,finish.");semaphore.release();}
}public class SemaTest {public static void main(String[] args) {Semaphore s = new Semaphore(3);for (int i = 1; i <= 10; i++) {new Thread(new Parent(s, i+"")).start();}}
}

并发队列

并发队列也是并发包中的,他们都是线程安全的。
生产消费者模型中的缓冲buff就可以看作是一个并发队列
队列遵循规则:先进先出

并发队列有界和无界的区别?

Array数组规定长度,不能超过长度,就是有界的
无界支持无限制存放。

阻塞与非阻塞队列的区别?

生产者写入满的时候,即队列满了,线程进行等待;消费者当队列为空的时候,也进行等待,就是阻塞队列。

非阻塞的,满了或者空了线程不等待直接挂掉。

非阻塞式队列ConcurrentLinkedDeque

非阻塞式无界限安全队列 ConcurrentLinkedDeque和ConcurrentLinkedQueue,不同的是ConcurrentLinkedDueue是双向链表,因此ConcurrentLinkedDueue既可以当做队列也可当做栈来使用。

public class Qu {public static void main(String[] args) {ConcurrentLinkedDeque<String> concurrentLinkedDeque = new ConcurrentLinkedDeque<>();concurrentLinkedDeque.offer("张三");concurrentLinkedDeque.offer("李四");System.out.println(concurrentLinkedDeque.size());System.out.println(concurrentLinkedDeque.poll());System.out.println(concurrentLinkedDeque.size());System.out.println(concurrentLinkedDeque.poll());System.out.println(concurrentLinkedDeque.size());}
}

阻塞式队列BlockingQueue

BlockingQueue
常用的四个类是ArrayBlockingQueue、LinkedBlockingQueue,PriorityBlockingQueue和SynchronizedQueue

public class Qu {public static void main(String[] args) throws InterruptedException {ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(3);queue.add("张三");queue.add("李四");queue.add("王五");// 可阻塞的队列,超过界限超时2秒,挂掉queue.offer("老六",2,TimeUnit.SECONDS);System.out.println("阻塞2秒后结束");System.out.println(queue.size());System.out.println(queue.poll());System.out.println(queue.poll());System.out.println(queue.poll());System.out.println(queue.poll());}
}

BlockingQueue和ConcurrentLinkedDeque的区别?

BlockingQueue可阻塞,并且时间有界限,ConcurrentLinkedDeque不阻塞

生产者消费者例子

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.SneakyThrows;import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;import static java.lang.Thread.sleep;@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
class ProducerThread extends Thread {private BlockingQueue<String> blockingQueue;private static AtomicInteger count = new AtomicInteger();private volatile Boolean allowProducing = true;@SneakyThrows@Overridepublic void run() {System.out.println("生产者线程启动");while (allowProducing) {System.out.println("正在生产队列");String data = count.incrementAndGet() + "";boolean offer = blockingQueue.offer(data);if (offer) {System.out.println("生产者添加队列成功");} else {System.out.println("生产者添加队列失败");}sleep(1000);}System.out.println("生产者线程停止");}public void stopThread() {this.allowProducing = false;}
}@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
class Consumer extends Thread {private BlockingQueue<String> blockingQueue;private volatile Boolean allowConsume = true;@SneakyThrows@Overridepublic void run() {System.out.println("消费者线程启动");while (allowConsume) {String data = blockingQueue.poll(2, TimeUnit.SECONDS);if (data != null) {System.out.println("消费者获取数据: " + data);} else {System.out.println("消费者获取数据失败");this.allowConsume = false;}sleep(1000);}}public void stopThread() {this.allowConsume = false;}
}public class TestScz {public static void main(String[] args) throws InterruptedException {LinkedBlockingDeque<String> blockingDeque = new LinkedBlockingDeque<>(10);ProducerThread producerThread1 = new ProducerThread(blockingDeque, true);ProducerThread producerThread2 = new ProducerThread(blockingDeque, true);Consumer consumer = new Consumer(blockingDeque, true);producerThread1.start();producerThread2.start();consumer.start();Thread.sleep(10 * 1000);producerThread1.stopThread();producerThread2.stopThread();}
}

闭关修炼(四)并发包/类相关推荐

  1. Java闭关修炼64课 很适合新手学习的JAVA视频教程

    Java闭关修炼64课 很适合新手学习的JAVA视频教程 java闭关修炼第一课 什么是java(1).rar   java闭关修炼第一课 什么是java.rar   java闭关修炼第七课 基础语言 ...

  2. 闭关修炼21天终于拿到offer

    闭关修炼21天,"啃完"283页pdf,我终于4面拿下字节跳动offer Java程序猿阿谷 写在开篇 闲话(长话短说): 今年的开端有些特殊,疫情的缘故对我们的生活造成了很大的影 ...

  3. 闭关修炼30天,“啃透”这658页PDF,成功定级阿里P7

    今年的开端有些特殊,疫情的缘故对我们的生活造成了很大的影响,这对于一名求职者来说,更是添上了一堵"难墙",虽然金三银四已经过去,但我们决不能够再错过秋招的机会,该抓住的就要抓住.现 ...

  4. 开始闭关修炼 冥思微软之大未来

    盖茨开始闭关修炼 冥思微软之大未来 (2005.03.30)   华尔街日报   <script src="/adv/news_ad.asp?news_id=20356&sub ...

  5. 盖茨开始闭关修炼 冥思微软之大未来

    盖茨开始闭关修炼 冥思微软之大未来 http://www.csdn.net/news/newstopic/20/20356.shtml 上个月,如果你有机会一窥蕴藏了科技行业未来的水晶球,那么就会看到 ...

  6. 盖茨开始闭关修炼 冥思微软之大未来(引用)

    没有什么可说的,一切都值得让我们思考,ms, bill. 上个月,如果你有机会一窥蕴藏了科技行业未来的水晶球,那么就会看到太平洋西北沿岸一片浓密的雪松林中一条曲折蜿蜒的道路,它带你穿越林海通往科技业顶 ...

  7. Windows移动开发(二)——闭关修炼

    一些武侠小说里的大人物,为了争夺武林盟主,号召天下,经常闭关修炼一段时间,闭关期间只能接触送饭的人,并且关外还有很多守卫的人员.还有,无论是篮球还是足球运动员,他们在真正接触球之前,都必须做很长一段时 ...

  8. 十月一“闭关修炼”,读完这些Java技术栈,愿金九银十过五斩六

    十月一由于疫情还是有很多人为了安全不会去旅游,实际上,对于有跳槽打算的人来说,现在正是"闭关修炼"的好时机,但很多人不知道从何开始学习,也正为即将到来的金九银十发愁!今天,小编就要 ...

  9. 来自菜鸟的逆袭,闭关修炼一个月,出关后成功拿下阿里,蚂蚁金服,美团三个大厂意向书!

    前言 楼主来自重庆一个普通的本科大学计算机学院,自己曾经在没拿到offer时也焦虑彷徨过,大大小小的公司自己也有投过,最终在自己闭关修炼一个月后成功斩获4个offer 腾讯 csig 后台开发 自我介 ...

  10. 张宇闭关修炼【超清pdf】

    2020张宇闭关修炼[超清]pdf 资料链接 https://shimo.im/docs/rOCr3qKLursLC5Mq/ 祝大家考研顺利! 根据工学.经济学.管理学各学科.专业对硕士研究生入学所应 ...

最新文章

  1. 分布式缓存的选择及问题
  2. 空间复杂度分段分段有序数组合并成有序(空间复杂度为O(1))
  3. 我已经把servlet-api.jar加到classpath中了,可还是无法编译servlet
  4. php 读取 linux 文件,PHP读取大文件,linux读取日志
  5. 每个程序员都应该挑战的6个项目
  6. C 运算符和语句总结
  7. P1866 编号 python
  8. Oracle笔记-Oracle基本结构及安装启动(windows版)
  9. 第一次作业_U201410737 _万学远
  10. logistic和logitraw
  11. 面对强势顾客,怎样应对才好?
  12. linux 分区顺序 boot,关于Liunx下的硬盘分区问题(/boot分区)?
  13. 测开面试题大全及答案(含测试基础|实例介绍|软件本地化测试等)
  14. 成考计算机专业难不难,成人高考计算机类难度大吗(成人大学难度)
  15. 2021年Facebook广告投放的9条建议
  16. 扩展名为bat的文件的创建
  17. 高中数学40分怎么办_高中数学40分怎么办?
  18. 谭浩强《C语言》学习1
  19. React入门——项目搭建
  20. 【信息系统项目管理师】信息系统主流开发方法之结构化方法、面向对象方法和原型法总结

热门文章

  1. bzoj4084【SDOI2015】bigyration
  2. 免费下载思科CCNP 642-353考试题库
  3. 简单叙述python的编程规范_简明 Python 编程规范
  4. python web前端 java ui学哪个好_学IT选Java还是Python?就业发展有何区别?
  5. 有关于论文投稿的问题
  6. window环境下thrift Compiler 编译步骤
  7. 手机kakao聊天能自动翻译 WhatsApp翻译 实时翻译
  8. Anaconda使用感悟
  9. CND(内容分发网络)前端的使用
  10. 清晰度、分辨率、像素、4K、HDR的区别