除了四种常见的同步器(发令枪、摇号器、栅栏和交换机),JUC还有所谓线程安全的容器、阻塞队列和一些特殊的类。其中常出现的就是线程安全的容器和阻塞队列。与其说这是两个大的分类,还不如说它就是两个用得最多的类:ConcurrentHashMap和ArrayBlockingQueue。
前面把线程相关的生命周期、关键字、线程池(ThreadPool)、ThreadLocal、CAS、锁和AQS都讲完了,现在就剩下怎么来用多线程了。而要想用好多线程,其实是可以取一些巧的,比如JUC(好多面试官喜欢问的JUC,就是现在要讲的JUC)。
接下来用AQS来实现一个实际的生活场景。比如周末带女票或男票去步行街吃饭,这时候人特别多,需要摇号,而且一次只能进去三张号(不按人头算,按叫到的号来算),该怎么实现呢?
Java中的AQS(AbstractQueuedSynchronizer,抽象队列同步器)是用来实现锁及其他同步功能组件的Java底层技术基础,java.util.concurrent包下大部分类的实现都离不开它。
在Java面试中,有一类高频问题会经常问到(火箭式问题):Java有几种锁?都是干嘛的?我想对于面试经验较为丰富的人,这个问题极有可能遇到过。不过我估计除了「死锁」大部分人都听过以外,其他的什么锁可能就不是那么清楚了。
CAS是Compare And Swap(比较与交换)的缩写,它用于实现多线程同步的原子指令,允许算法执行读-修改-写操作,而无需担心其他线程同时修改变量。说人话,意思就是它的操作过程足够细微,以至于线程都奈何不了它。
有了线程关键字解决线程安全问题,有了线程池解决效率问题,那还有什么问题是可以需要被解决的呢?——还真被这帮疯子攻城狮给找到了!
除了可以通过ThreadPoolExecutor自定义线程池外,同Stream API中的Collectors一样,多线程里的Executors类也提供了一组相关的线程池工具,可以直接拿来用,不用考虑用什么队列合适的问题。
线程池是个神器,用得好会非常地方便。其实主要是把常用那几个workQueue搞搞清楚,因为这几个在今后的工作中可能会用到,尤其是ArrayBlockingQueue,它和后面会说的另两个神器,可以说是是「线程三宝」。
一个线程的完整生命周期包括创建T1 + 运行T2 + 销毁T3。实际上T1 + T3的开销远远大于T2,如果有大量的并发请求,就会大大降低系统效率,严重影响系统性能,这就是为什么会引入线程池原因了。
Java中和线程相关的关键字就两:volatile和synchronized。volatile可懂可不懂,synchronized建议用代码块的方式实现同步。
从事Java开发这些年来,如果要问我Java当中最难的部分是什么?最有意思的部分是什么?最多人讨论的部分是什么?那我会毫不犹豫地说:多线程。Java多线程最大的特点,而且也是唯一确定的一件事,那就是:在多线程环境下,程序的运行结果是无法预料的,但这也正是它最有趣的地方。
在Java NIO的三大核心中,除了Channel和Buffer,剩下的就是Selector了。Selector的作用就是一句话:用最少的资源实现最多的操作,避免了线程切换带来的开销。
很多初学者不明白「缓冲」和「缓存」的区别,其实用大白话解释就是砧板和冰箱的区别。
NIO不但新增加了许多全新的类,而且还对原来的很多类进行了改写。之所以是NIO,是因为使用它的场景众多,譬如开发中必不可少的Tomcat,以及大名鼎鼎的Netty,而Netty更是把NIO发挥到了极致,成为了RPC技术事实上的标准,所以它在JDK1.7中又升级为了AIO(NIO2)。
Java在诞生之初就具备了文件读写能力,只不过那时候还是借用的Linux中的I/O概念,因此可以说Java的I/O体系基本上就是Linux内核I/O模型的翻版。I/O是Java中比较裹人的概念之二,非常枯燥,没办法。看看就行,理解不了那就多敲代码。
这个案例在我们后来的自研系统中发展成了一个内部的小工具,通过管理后台的功能按钮来动态创建、修改Elasticsearch的索引和文档,以及导出、导入数据等等,功能非常强大。我想,那些目前主流开发的框架也都是这么从小做起,一点点发展起来的吧。
学会了技术就要使用,否则很容易忘记,因为自然界压根就不存在什么代码、变量之类的玩意,这都是一些和生活常识格格不入的东西。只能多用多练,形成肌肉记忆才行。这里就结合实际案例再展示一下注解的用法。
搞过Java的码农都知道,在J2EE开发中ORM是一类很重要的框架,但其实它的本质一点都不复杂,通过对反射和注解的了解,就试着来实现咱们自己的缝合怪。
如果有些编程语言因为升级更新,替换掉了某些功能特性而导致开发受阻甚至不能使用,该怎么办呢?——这也难不倒科学家。他们想:既然码农可以写注释提醒自己不忘记代码是干什么的,那是不是也可以通过某种方法来提醒他们代码会出问题呢?还真被他们找到了,这就是注解!
在经典的GoF设计模式中,有一种模式叫做代理模式。而在代码实现上,反射可以非常优雅地实现一种所谓的动态代理。
Java反射的本质是:JVM得到编译过的.class文件后,加载到JVM中,通过Class获取到对象的各种信息,再根据这些信息创建所需的对象实例或变量的引用值。这一点,和侏罗纪公园中科学家复活恐龙的过程极其相似。
我觉得副业如果做得好,其实主业、副业之间是可以随时转换的。重点不在「主」或「副」,而在于「业」,事业的「业」。一个真正有价值的人,应该是不存在「主」「副」之分的。老板不是喜欢画饼嘛,副业做的好,还可以反向画饼,做老板的老板——双赢嘛,何乐而不为?为啥非要搞得跟仇人似的,一起赚钱不香吗。
搞懂20%的问题,然后举一反三——如果学习开发有捷径的话,那这就是。
泛型,历经千帆,归来仍是是少年!
说起KTV恐怕没几个人不知道的。虽然这玩意没有过去那么火热了,但喝了酒之后再去飙几个高八度的爆破音还是蛮爽的。但Java里面也有一个基础特性用到了KTV。
泛型讲到这里,如果能够全部明白,就可以真正畅快地去KTV嗨了。而泛型其他的知识点,像什么无界通配符、泛型参数一致性、多重限定、基类劫持接口、自限定类型、循环泛型等乱七八糟的可以统统不去管了,因为很多工程师一辈子的职业生涯中几乎都碰不到它们。
Copyright © 2005-2025 51CTO.COM 版权所有 京ICP证060544号