Java高并发综合

这篇文章是研一刚入学时写的,今天整理草稿时才被我挖出来。当时混混沌沌的面试,记下来了一些并发的面试问题,很多还没有回答。到现在也学习了不少并发的知识,回过头来看这些问题和当时整理的答案,漏洞百出又十分可笑。发表出来权当对自己的一个提醒——如果不能一直进步,你就看不到当初傻逼的自己。


曾经,我在面试Java研发实习生时最常听到的一句话就是:

搞Java怎么能不学并发呢?

没错,真的是经过了面试官的无数鄙视,我才知道Java并发编程在Java语言中的重要性。

并发模型

悲观锁和乐观锁的理解及如何实现,有哪些实现方式?

悲观锁

悲观锁假设最坏的情况(如果你不锁门,那么捣蛋鬼就会闯入并搞得一团糟),并且只有在确保其他线程不会干扰(通过获取正确的锁)的情况下才能执行下去。

常见实现如独占锁等。

安全性更高,但在中低并发程度下的效率更低。

乐观锁

乐观锁借助冲突检查机制来判断在更新过程中是否存在其他线程的干扰,如果存在,这个操作将失败,并且可以重试(也可以不重试)。

常见实现如CAS等。

部分乐观锁削弱了一致性,但中低并发程度下的效率大大提高。

并发编程

Java中如何创建一个线程

从面相接口的角度上讲,实际上只有一种方法实现Runable接口;但Thread类为线程操作提供了更多的支持,所以通常做法是实现Runable接口,实例化并传入Thread类的构造函数。

  1. 继承Thread,覆写run方法
  2. 实现Runable接口,覆写run方法

Vector(HashTable)如何实现线程安全

通过synchronized关键字修饰每个方法。

依据synchronized关键字引申出以下问题。

synchronized修饰方法和修饰代码块时有何不同

持有锁的对象不同:

  1. 修饰方法时:this引用的当前实例持有锁
  2. 修饰代码块时:要指定一个对象,该对象持有锁

从而导致二者的意义不同:

  1. 同步代码块在锁定的范围上可能比同步方法要小,一般来说锁的范围大小和性能是成反比的。
  2. 修饰代码块可以选择对哪个对象加锁,但是修饰方法只能给this对象加锁。

ConcurrentHashMap的如何实现线程安全

ConcurrentHashMap的线程安全实现与HashTable不同:

  1. 可以将ConcurrentHashMap理解为,不直接持有一个HashMao,而是用多个Segment代替了一个HashMap。但实际实现的Map部分和HashMap的原理基本相同,对脚标取模来确定table[i]所属段,从而对不同的段获取不同的段锁。
  2. 每个Segment持有一个锁,通过分段加锁的方式,既实现了线程安全,又兼顾了性能

Java中有哪些实现并发编程的方法

要从最简单的答起,业界最常用的是重点,有新意就放在最后。

  1. synchronized关键字
  2. 使用继承自Object类的wait、notify、notifyAll方法
  3. 使用线程安全的API和集合类:
    1. 使用Vector、HashTable等线程安全的集合类
    2. 使用Concurrent包中提供的ConcurrentHashMap、CopyOnWriteArrayList、ConcurrentLinkedQueue等弱一致性的集合类
    3. 在Collections类中有多个静态方法,它们可以获取通过同步方法封装非同步集合而得到的集合,如List list = Collection.synchronizedList(new ArrayList())
    4. 使用原子变量、volatile变量等
  4. 使用Concurrent包中提供的信号量Semaphore、闭锁Latch、栅栏Barrier、交换器Exchanger、Callable&Future、阻塞队列BlockingQueue等.
  5. 手动使用Lock实现基于锁的并发控制
  6. 手动使用Condition或AQS实现基于条件队列的并发控制
  7. 使用CAS和SPIN等实现非阻塞的并发控制
  8. 使用不变类
  9. 其他并发模型还没有涉及

从而引申出如下问题:

ConcurrentHashMap的的实现原理(见前)

CopyOnWriteArrayList的复制操作发生在什么时机

synchronizedList&Vector的区别

  1. synchronizedList的实现中,synchronized关键字修饰代码块;Vector的实现中修饰方法。
  2. synchronizedList只封装了add、get、remove等代码块,但Iterator却不是同步的,进行遍历时要手动进行同步处理;Vector中对Iterator也进行了加锁。
  3. synchronizedList能够将所有List实现类封装为同步集合,其内部持有的仍然是List的实现类(ArrayList/LinkedList),所以除同步外,几乎只有该实现类和Vector的区别。

synchronized修饰方法和修饰代码块时有何不同(见前)

信号量Semaphore、闭锁Latch、栅栏Barrier、交换器

Exchanger、Callable&Future、阻塞队列BlockingQueue的实现原理

ConcurrentLinkedQueue的插入算法

算法核心可概括为两步:

  1. 先检测是否是中间状态(SPIN)
  2. 再尝试CAS插入

详细待补充。

参考:

在java中wait和sleep方法的不同?

最大的不同是在等待时wait会释放锁,而sleep一直持有锁。Wait通常被用于线程间交互,sleep通常被用于暂停执行。

为什么wait, notify 和 notifyAll这些方法不在thread类里面?

主要原因是JAVA提供的锁是对象级的而不是线程级的,每个对象都有锁,通过线程获得。由于wait,notify和notifyAll都是锁级别的操作,所以把他们定义在Object类中因为锁属于对象。

为什么wait和notify方法要在同步块中调用?

Java API强制要求这样做,如果你不这么做,你的代码会抛出IllegalMonitorStateException异常。还有一个原因是为了避免wait和notify之间产生竞态条件。

为什么你应该在循环中检查等待条件?

处于等待状态的线程可能会收到错误警报和伪唤醒,如果不在循环中检查等待条件,程序就会在没有满足结束条件的情况下退出。

Java线程池中submit() 和 execute()方法有什么区别?

两个方法都可以向线程池提交任务,execute()方法的返回类型是void,它定义在Executor接口中, 而submit()方法可以返回持有计算结果的Future对象,它定义在ExecutorService接口中,它扩展了Executor接口,其它线程池类像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有这些方法。

volatile 变量和 atomic 变量有什么不同?

Volatile变量可以确保先行关系,即写操作会发生在后续的读操作之前, 但它并不能保证原子性。例如用volatile修饰count变量那么 count++ 操作就不是原子性的。而AtomicInteger类提供的atomic方法可以让这种操作具有原子性如getAndIncrement()方法会原子性的进行增量操作把当前值加一,其它数据类型和引用变量也可以进行相似操作。

为什么Thread类的sleep()和yield ()方法是静态的?

Thread类的sleep()和yield()方法将在当前正在执行的线程上运行。所以在其他处于等待状态的线程上调用这些方法是没有意义的。这就是为什么这些方法是静态的。它们可以在当前正在执行的线程中工作,并避免程序员错误的认为可以在其他非运行线程调用这些方法。


本文链接:Java高并发综合
作者:猴子007
出处:https://monkeysayhi.github.io
本文基于 知识共享署名-相同方式共享 4.0 国际许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名及链接。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,601评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,367评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,249评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,539评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,967评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,929评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,098评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,825评论 0 207
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,609评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,796评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,282评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,603评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,277评论 3 242
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,159评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,959评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,079评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,874评论 2 277

推荐阅读更多精彩内容

  • 曾经,我在面试Java研发实习生时最常听到的一句话就是: 搞Java怎么能不学并发呢? 没错,真的是经过了面试官的...
    野梦M阅读 455评论 0 2
  • Java SE 基础: 封装、继承、多态 封装: 概念:就是把对象的属性和操作(或服务)结合为一个独立的整体,并尽...
    Jayden_Cao阅读 2,051评论 0 8
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,020评论 11 349
  • 下面是我自己收集整理的Java线程相关的面试题,可以用它来好好准备面试。 参考文档:-《Java核心技术 卷一》-...
    阿呆变Geek阅读 14,678评论 14 507
  • ——鸿鸾禧 结婚到底为了什么,很多人就这么浑浑噩噩的过了一辈子。 张爱玲笔下的玉清因为结婚,终于能够发泄自己的购物...
    柠懵哒哒阅读 486评论 0 0