Author:汪文君
No description
Tags
Support Statistics
¥.00 ·
0times
Text Preview (First 20 pages)
Registered users can read the full content for free
Register as a Gaohf Library member to read the complete e-book online for free and enjoy a better reading experience.
Page
1
(This page has no text content)
Page
2
Java核心技术系列 Java高并发编程详解:深入理解并发核心库 汪文君 著 ISBN:978-7-111-65770-5 本书纸版由机械工业出版社于2020年出版,电子版由华章分社(北京 华章图文信息有限公司,北京奥维博世图书发行有限公司)全球范围 内制作与发行。 版权所有,侵权必究 客服热线:+ 86-10-68995265 客服信箱:service@bbbvip.com 官方网址:www.hzmedia.com.cn 新浪微博 @华章数媒 微信公众号 华章电子书(微信号:hzebook)
Page
3
目 录 推荐序一 推荐序二 推荐序三 推荐序四 前言 第1章 JMH 1.1 JMH简介 1.2 JMH快速入门 1.2.1 用main方法进行测试 1.2.2 用JMH进行微基准测试 1.3 JMH的基本用法 1.3.1 @Benchmark标记基准测试方法 1.3.2 Warmup以及Measurement 1.3.3 四大BenchmarkMode 1.3.4 OutputTimeUnit 1.3.5 三大State的使用 1.3.6 @Param的妙用 1.3.7 JMH的测试套件(Fixture) 1.3.8 CompilerControl 1.4 编写正确的微基准测试以及高级用法 1.4.1 编写正确的微基准测试用例 1.4.2 一些高级的用法 1.5 JMH的Profiler 1.5.1 StackProfiler 1.5.2 GcProfiler 1.5.3 ClassLoaderProfiler 1.5.4 CompilerProfiler 1.6 本章总结 第2章 Java并发包之原子类型详解 2.1 AtomicInteger详解 2.1.1 性能测试对比 2.1.2 AtomicInteger的基本用法 2.1.3 AtomicInteger内幕 2.1.4 AtomicInteger总结
Page
4
2.2 AtomicBoolean详解 2.2.1 AtomicBoolean的基本用法 2.2.2 AtomicBoolean内幕 2.2.3 Try Lock显式锁的实现 2.2.4 AtomicBoolean总结 2.3 AtomicLong详解 2.4 AtomicReference详解 2.4.1 AtomicReference的应用场景 2.4.2 AtomicReference的基本用法 2.4.3 AtomicReference的内幕 2.4.4 AtomicReference总结 2.5 AtomicStampedReference详解 2.5.1 CAS算法ABA问题 2.5.2 AtomicStampedReference详解 2.5.3 AtomicStampedReference总结 2.6 AtomicArray详解 2.7 AtomicFieldUpdater详解 2.7.1 原子性更新对象属性 2.7.2 注意事项 2.7.3 AtomicFieldUpdater总结 2.8 sun.misc.Unsafe详解 2.8.1 如何获取Unsafe 2.8.2 JNI、Java和C/C++混合编程 2.8.3 危险的Unsafe 2.8.4 sun.misc.Unsafe总结 2.9 本章总结 第3章 Java并发包之工具类详解 3.1 CountDownLatch工具详解 3.1.1 等待所有子任务结束 3.1.2 CountDownLatch的其他方法及总结 3.2 CyclicBarrier工具详解 3.2.1 等待所有子任务结束 3.2.2 CyclicBarrier的循环特性 3.2.3 CyclicBarrier的其他方法以及总结 3.2.4 CyclicBarrier VS. CountDownLatch 3.3 Exchanger工具详解 3.3.1 一对线程间的数据交换
Page
5
3.3.2 Exchanger的方法详解 3.3.3 Exchanger总结 3.4 Semaphore工具详解 3.4.1 Semaphore限制同时在线的用户数量 3.4.2 使用Semaphore定义try lock 3.4.3 Semaphore其他方法详解 3.4.4 扩展Semaphore增强release 3.4.5 Semaphore总结 3.5 Phaser工具详解 3.5.1 Phaser的基本用法 3.5.2 Phase(阶段)以及Phaser方法详解 3.5.3 Phaser层级关系 3.5.4 Phaser总结 3.6 Lock&ReentrantLock详解 3.6.1 Lock及ReentrantLock方法详解 3.6.2 正确使用显式锁Lock 3.6.3 ReentrantLock VS. Synchronized关键字 3.6.4 显式锁Lock总结 3.7 ReadWriteLock&ReentrantReadWriteLock详解 3.7.1 读写锁的基本使用方法 3.7.2 读写锁的方法 3.7.3 基准测试性能对比 3.7.4 读写锁总结 3.8 Condition详解 3.8.1 初识Condition 3.8.2 Condition接口方法详解 3.8.3 使用Condition之生产者消费者 3.8.4 Condition总结 3.9 StampedLock详解 3.9.1 读写锁的饥饿写问题 3.9.2 StampedLock的使用 3.9.3 与其他锁的性能对比 3.9.4 StampedLock总结 3.10 Guava之Monitor详解 3.10.1 Monitor及Guard 3.10.2 Monitor的其他方法 3.10.3 Monitor总结
Page
6
3.11 Guava之RateLimiter详解 3.11.1 RateLimiter的基本使用 3.11.2 RateLimiter的限流操作——漏桶算法 3.11.3 令牌环桶算法 3.11.4 RateLimiter总结 3.12 本章总结 第4章 Java并发包之并发容器详解 4.1 链表 4.1.1 基本的链表 4.1.2 优先级链表 4.1.3 跳表(SkipList) 4.1.4 链表总结 4.2 BlockingQueue(阻塞队列) 4.2.1 ArrayBlockingQueue 4.2.2 PriorityBlockingQueue 4.2.3 LinkedBlockingQueue 4.2.4 DelayQueue 4.2.5 SynchronousQueue 4.2.6 LinkedBlockingDeque 4.2.7 LinkedTransferQueue 4.2.8 BlockingQueue总结 4.3 ConcurrentQueue(并发队列) 4.3.1 并发队列的性能 4.3.2 并发队列在使用中需要注意的问题 4.3.3 并发队列总结 4.4 ConcurrentMap(并发映射) 4.4.1 ConcurrentHashMap简介 4.4.2 ConcurrentSkipListMap简介 4.4.3 并发映射总结 4.5 写时拷贝算法(Copy On Write) 4.5.1 CopyOnWrite读实现操作分析 4.5.2 CopyOnWrite写实现操作分析 4.5.3 CopyOnWrite总结 4.6 高并发无锁(Lock Free)数据结构的实现 4.6.1 高并发无锁链表的实现 4.6.2 Lock Free数据结构的测试 4.6.3 本节总结
Page
7
4.7 本章总结 第5章 Java并发包之ExecutorService详解 5.1 Executor&ExecutorService详解 5.1.1 ThreadPoolExecutor详解 5.1.2 ScheduledExecutorService详解 5.1.3 关闭ExecutorService 5.1.4 Executors详解 5.1.5 ExecutorService总结 5.2 Future和Callback 5.2.1 Future详解 5.2.2 ExecutorService与Future 5.2.3 Future的不足之处 5.2.4 Google Guava的Future 5.2.5 Future总结 5.3 ForkJoinPool详解 5.3.1 Fork/Join Framework介绍 5.3.2 ForkJoinTask详解 5.3.3 ForkJoinPool总结 5.4 CompletionService详解 5.4.1 ExecutorService执行批量任务的缺陷 5.4.2 CompletionService详解 5.4.3 CompletionService总结 5.5 CompletableFuture详解 5.5.1 CompletableFuture的基本用法 5.5.2 任务的异步运行 5.5.3 异步任务链 5.5.4 合并多个Future 5.5.5 多Future的并行计算 5.5.6 错误处理 5.5.7 JDK 9对CompletableFuture的进一步支持 5.5.8 CompletableFuture总结 5.6 本章总结 第6章 Java Streams详解 6.1 Stream介绍及其基本操作 6.1.1 如何创建Stream 6.1.2 Stream之Intermediate操作 6.1.3 Stream之Terminal操作
Page
8
6.1.4 NumericStream详解 6.1.5 Stream总结 6.2 Collector在Stream中的使用 6.2.1 初识Collector 6.2.2 Collectors用法详解 6.2.3 自定义Collector 6.2.4 Collector总结 6.3 Parallel Stream详解 6.3.1 并行流Parallel Stream 6.3.2 Spliterator 详解 6.3.3 Spliterator总结 6.4 本章总结 第7章 Metrics(Powerful Toolkit For Measure) 7.1 Metrics快速入门 7.1.1 如何监控度量应用程序 7.1.2 Metrics环境搭建 7.2 五大Metric详解 7.2.1 Meter 7.2.2 Gauge 7.2.3 Counter 7.2.4 Histogram 7.2.5 Timer 7.3 Reporter详解 7.3.1 ConsoleReporter 7.3.2 LogReporter 7.3.3 JMXReporter 7.3.4 CsvReporter 7.4 Metrics Plugins 7.4.1 Health Check 7.4.2 JVM Instrumentation 7.5 深入Metrics源码 7.5.1 MetricRegistry如何工作 7.5.2 Reporter如何工作 7.5.3 拾遗补漏 7.6 本章总结
Page
9
推荐序一 恭喜汪文君老师又写新书了。 强烈推荐所有以成为Java高手、架构师为目标的读者阅读本书。 本书深入讲述了Java高并发编程的相关内容,覆盖面广而全,可以将 其看作Java高并发编程的一本百科全书。Java高并发编程是Java编程 比较高阶的部分,讲述这部分内容的书不多,这本书的出版可以看作 一个里程碑。 在知识体系方面,本书既有广度又有深度。在广度方面,本书覆 盖了Java高并发编程的语法、高级用法与Profiler、类型详解、开发 工具、高并发的数据机构及原理、实践编程的详细用法、框架的用 法,以及典型场景下的应用案例。在深度方面,本书不仅对基于Java 高并发编程的所有类的说明、用法与经典案例都进行了详尽的论述, 而且对Java在这方面的最新发展与应用给出了深入浅出的解释。 随着近几年云原生、容器化、分布式计算的逐渐发展和普及,以 及微服务架构的演进与兴起,Java高并发编程在设计与编程中的地位 越来越重要。Java高并发编程已经成为架构师、资深编程人员进行分 布式协作设计、服务设计、模块开发所必需的基本功,也是理解、使 用、优化Web容器、JEE容器、云原生基础设施组件所不可或缺的基本 技能。 在本书中,大家不仅能够学到深度、专业的编程知识,还能感受 到汪文君老师专注地提高编程技能的态度,始终如一地贡献、分享 Java专业知识与经验的精神,以及持续学习、持续成长的进取精神。 在这些方面,他同样是我学习的楷模。 我们在学习书中的内容时,一定要动手编码,实践书中的知识。 理论上,成为专业人员要经历四个阶段:无意识无能、有意识无能、 有意识能力、无意识能力。通过不断学习、持续地实践和编程,最终 将编程能力内化为个人的无意识能力。让我们的专业之路从这本书开 始吧!
Page
10
东软集团移动互联网事业部首席技术官 徐景辉
Page
11
推荐序二 首先,我很荣幸可以再次受到邀请为Alex的新作写推荐序,Alex 的第二本书《Java高并发编程详解:深入理解并发核心库》是一本内 容非常全面的参考图书,该书可以帮助你充分了解和使用JVM生态圈中 最重要的技术内容之一——Java并发核心库。 本书比较全面地探讨了并发核心库的各个方面,从基准测试JMH开 始,到原子类型、并发工具、并发容器、ExecutorService、Java 8 Stream知识,以及最后的性能度量工具库Metrics,每一个细节的概 念、使用方法、适合的应用场合、应避免使用的场合书中都进行了详 细解释,并且都配备了非常详细的实例,可以帮助读者快速建立对其 的理解和认识。 对于想学习Java并发编程的人或有一定经验的开发人员来说,如 果他们希望有什么资料能在以后的工作中为自己提供专业的参考,那 么我强烈推荐这本书。 OSL公司首席技术官 Andrew Davidson
Page
12
推荐序三 以我从事云计算平台研发架构及咨询近10年的经验来看,弹性 云,以及服务组件免费、资源付费的模式将是一个成熟的模式,而这 就要求开发人员在节省资源的前提下能够开发出高性能的应用程序, 合理充分地利用软硬件的资源,并且以廉价的成本为企业创造高性能 的服务产品。这看起来似乎很难,没错!这确实不太容易。想象一 下,我们基于AWS lambda架构设计开发的Serverless程序,在同等 CPU、内存等其他服务调用的情况下,如果程序员能够开发并受理更多 的业务量、提供更多的并发量,势必会更多地受到老板的喜爱和公司 的重视。 这一观点同样也适用于现在越来越多的基于物联网的硬件设备。 一般情况下,基于物联网的硬件终端,其软硬件配置短时间内很难达 到普通PC甚至用于生产环境的服务器的水平,那么在有限的资源上开 发出响应速度快、运算能力强的计算程序就显得尤为重要了。 本书中所讲述的内容给出了部分解决之道,Alex非常详细地介绍 了Java并发包中的并发知识及技术细节,通过对它们的学习与应用, 相信普通的开发者也可以开发出高性能、高吞吐量的应用程序。 Alex是一个非常有耐心的人,本书内容的系统化组织、知识点的 细致讲述深深地吸引了我,本书的完成将是非常耗费时间的一次写作 之旅,我很佩服他对基准测试的深刻认识以及对原子类型的完美解 读。 作为一个Java程序员,哦不,作为一个基于JVM语言开发程序的工 程师,我强烈推荐此书作为你的参考书籍。 EY安永金融服务咨询部云总监 Srimanth Rudraraju
Page
13
推荐序四 “开发正确的程序是比较难的,开发正确的高并发多线程应用则 更是难上加难。”我已经记不清这句话出自何处,但是我完全认同这 句话所表达的观点。 我已经有20多年的软件开发经验,并且现在仍然乐于此道。正如 Alex一样,我也喜欢琢磨和分析每一次软件开发过程中遇到的细节, 这也是为什么我们彼此在仅有的几次社区探讨之后,就经常保持沟通 与联络,我欣赏他愿意为了所从事的事业投入大量的热情和时间的精 神。 让我们重新回到关于本书的话题中来。本书内容涵盖非常广泛, 系统性地且有条理地讲述了Java并发包中的每一个常用工具及类。这 些类与工具是全体Java从业人员多年的宝贵积累和产物,是通过无数 次的探讨和实践总结归纳出的最佳实践。Alex将它们悉数详细解释给 读者,这是一件非常了不起的事情,他一定也为此牺牲了很多陪伴家 人的时间。 开发正确的高并发多线程程序是极为困难的,不过不用担心,学 习并且使用优秀的并发库就可以帮我们屏蔽这些令人担忧的问题,这 也是本书的价值所在。 希望该书的读者在阅读和学习之后能有一定的收获。 软件架构师、Apache软件基金会成员、开源软件Tomcat PMC成 员 Igal
Page
14
前言 为什么写这本书 在我的第一本书《Java高并发编程详解:多线程与架构设计》出 版之后,我随即开始了第二本书《Java高并发编程详解:深入理解并 发核心库》的写作。这本书作为第一本书的延续,主要内容将围绕 Java并发包的使用场景展开;同时还增加了JMH基准测试工具的内容 (目前,最新的JDK版本中已经引入了该工具,并作为标准库之一发 布);引入了Java 8 Stream的相关内容,尤其是还分析了与高并发相 关的并行流;在本书的最后还介绍了性能度量工具Metrics(该类库目 前已经成为业界实质上的度量标准,很多开源系统、商业软件中都会 采用它)。 如果说我写作第一本书只是一次偶然性的尝试,那么这本书的写 作则是一次必然性的使命,是对读者和出版社的一个交代与承诺。为 了使得Java高并发编程的相关内容尽可能系统化和完善,必须完成对 并发包的介绍。这里,我要向伟大的Doug Lea大师致敬,由于他孜孜 不倦的努力、精益求精的敬业态度, Java程序员才能以较低的成本和 相对安全的方式来处理非常复杂的高并发多线程场景。 本书中的所有内容都来源于我的网络视频课程。每一套课程推出 后都在交流群中引起热烈讨论,我将这些讨论、学习者提出的疑惑以 及自己对内容的重新思考全部融入本书中,以使本书中所涉及的知识 点尽可能完善与成熟。 读者对象 计算机相关专业的在校学生 Java开发工程师 从事Java系统架构的架构师 使用Java作为开发语言的公司与组织
Page
15
开设Java课程的专业院校 开设Java课程的培训机构 如何阅读本书 本书共7章,逻辑上可分为四部分。第一部分(第1章)详细介绍 了JMH(Java Micro benchmark Harness)基准测试工具的使用细节。 该工具是由Oracle JVM开发团队相关成员开发的,借助它,开发者将 能足够了解自己所编写的程序代码,以及程序在运行期的精确性能表 现。在本书的其他章节中,我们对API之间的性能进行对比时主要也是 依赖于该工具,因此在学习本书的其他章节之前,最好能够先掌握该 部分内容。笔者在此强烈推荐开发者将JMH纳入自己日常的“兵器库” 中,以便随时随地使用。 第二部分(第2~5章)主要围绕Java并发包进行展开,内容包 括:Java的原子类型及其底层原理(第2章);Java的并发工具集(第 3章),其中还穿插了Google Guava的部分内容;Java的并发容器(第 4章),包括阻塞队列BlockingQueue和并发容器等内容;Java的 ExecutorService(第5章),以及Future家族成员的详解。 第三部分(第6章)主要介绍自Java 8引入的Stream,并且重点解 释了具备高并发能力的并行流原理,以及如何自定义并行流等相关内 容。 第四部分(第7章)主要介绍Metrics这个比较小巧的度量工具 集。目前Metrics已经成为事实上的度量标准,在很多开源软件、框架 和平台中都能看到对它的使用,比如Apache的Kafka、Spark、Storm、 Spring Cloud等都是使用Metrics作为系统运行性能指标收集的手段。 勘误和支持 由于作者的水平有限,写作时间仓促,书中难免会出现一些错误 或者不准确的地方,恳请读者批评指正。如果你在阅读的过程中发现 有任何问题,都欢迎将宝贵的意见发送到我的个人邮箱 532500648@qq.com。我真挚地期待着你的建议和反馈,由于个人时间
Page
16
有限,在反馈较多的情况下,如果不能第一时间回复你的邮件还望海 涵。 致谢 首先,我要感谢我的父亲,即使我早已成年,但在父亲的心里我 仍是个孩子,隔三差五地提醒我注意休息,按时吃饭,我每到一个新 城市,他都会关注这个城市的天气预报。作为一个七十多岁的老人, 自从得知我炒股之后,他甚至开始关注股市的涨跌,生怕大盘不好时 我会想不开,真是可怜天下父母心。人到中年回到家中,可以痛痛快 快地喊一声“爸”,这已经是老天对我最大的善意了。 感谢我的妻子照顾我的生活,打理家里的琐事,在小孩的养育中 承担了太多的责任,将我们两岁的双胞胎宝宝培养得如此暖心和乖 巧,使得我有更多的精力和时间投入事业之中。感谢我的妻子的支持 和理解,感谢你倾心倾力的付出。 感谢我家的双胞胎宝贝汪子敬、汪子兮兄妹,你们的加入让整个 家庭变得更加温暖与温馨,为我们这个家带来欢乐。希望时间慢点 走,这样我就可以更多地与你们一起嬉戏、举高高、骑大马、打地 鼠、躲猫猫……无论是在路途中还是在工作休息时,你们的视频、照 片、欢声与笑语填充着我所有的碎片时间。 感谢徐景辉(东软集团移动互联网研发部技术总监)一如既往地 为我提供帮助,在我的职业生涯中,你一直作为我的导师和榜样,给 我启迪,给我思路。感谢你继续为我的新书写推荐序。 感谢Andrew Davidson(定居在香港的澳大利亚人,OSL公司首席 技术官)在写作本书的过程中为我提供宝贵的建议和相关的资料,你 对我的每次求助都是有求必应,能够耐心地听我用蹩脚的英语表达我 遇到的问题。感谢你再次抽出宝贵的个人时间为本书写推荐序。 感谢Srimanth Rudraraju(印度裔的英国人,EY安永金融服务咨 询部云总监)提出的宝贵建议,当我将部分章节翻译成英文版本发送 给你审阅时,你不仅耐心地读完,而且与我讨论其中的一些细节,还
Page
17
提出了你的看法。同样感谢你为本书写推荐序。在与你共事的那段日 子里,你旺盛的精力和强大的脑容量令我印象深刻。 感谢Igal(来自美国加州,软件架构师,Apache软件基金会成 员,开源软件Tomcat PMC成员,出版了多本图书,发表了多篇论文, 拥有个人专利发明,Stack overflow的贡献者)。因在Stack overflow社区对相关问题进行讨论,得以与你相识,感谢你为我答疑 解惑,同时感谢你耐心地阅读本书翻译成英文版的部分章节,并为本 书写推荐序。 感谢我所在的公司,感谢我所在的团队,如此优秀的你们在工作 中给了我很多支持和帮助,与你们共事我很荣幸,你们教会了我很 多,也帮我分担了很多,感谢你们。 谨以此书,献给我最亲爱的家人,以及众多热爱Java开发的朋友 们。 汪文君(Alex Wang) 2020年5月于兰州
Page
18
第1章 JMH 1.1 JMH简介 JMH是Java Micro Benchmark Harness的简写,是专门用于代码微 基准测试的工具集(toolkit)。JMH是由实现Java虚拟机的团队开发 的,因此他们非常清楚开发者所编写的代码在虚拟机中将会如何执 行。 由于现代JVM已经变得越来越智能,在Java文件的编译阶段、类的 加载阶段,以及运行阶段都可能进行了不同程度的优化,因此开发者 编写的代码在运行中未必会像自己所预期的那样具有相同的性能体 现,JVM的开发者为了让普通开发者能够了解自己所编写的代码运行的 情况,JMH便因此而生。 JMH的官网地址:http://openjdk.java.net/projects/code- tools/jmh/。 1.2 JMH快速入门 在开始学习JMH之前,我们先来看一个不太严谨的性能测试方案 (也许你平时就是这么做的),比较常见的List有ArrayList和 LinkedList,在选取这两个API作为你程序中的数据容器时,我们先对 比一下这两者的add方法在性能上的差异,从而挑选出一个对性能较好 的容器应用在程序开发之中。 1.2.1 用main方法进行测试 程序员通常会将一些简单的测试交给一个main函数来完成,比如 对比两种List容器的add方法的性能时,我们将分别对其进行十组测 试,每组测试都将会对List执行1 000 000次的add调用,然后通过最
Page
19
大值、最小值、平均值的方式对其进行对比(当然,这里并不考虑不 同容器的内存开销,事实上,ArrayList和LinkedList在使用的过程 中,它们的内存开销肯定是不一样的)。 程序代码:ArrayListVSLinkedList.java package com.wangwenjun.concurrent.jmh; import com.google.common.base.Stopwatch; import com.google.common.base.Strings; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; public class ArrayListVSLinkedList { private final static String DATA = "DUMMY DATA"; private final static int MAX_CAPACITY = 1_000_000; private final static int MAX_ITERATIONS = 10; private static void test(List<String> list) { for (int i = 0; i < MAX_CAPACITY; i++) { list.add(DATA); } } private static void arrayListPerfTest(int iterations) { for (int i = 0; i < iterations; i++) { final List<String> list = new ArrayList<>(); final Stopwatch stopwatch = Stopwatch.createStarted(); test(list); System.out.println(stopwatch.stop() .elapsed(TimeUnit.MILLISECONDS)); } } private static void linkedListPerfTest(int iterations) {
Page
20
for (int i = 0; i < iterations; i++) { final List<String> list = new LinkedList<>(); final Stopwatch stopwatch = Stopwatch.createStarted(); test(list); System.out.println(stopwatch.stop() .elapsed(TimeUnit.MILLISECONDS)); } } public static void main(String[] args) { arrayListPerfTest(MAX_ITERATIONS); System.out.println(Strings.repeat("#", 100)); linkedListPerfTest(MAX_ITERATIONS); } } 运行上面的程序,我们会得出如下的数据(如图1-1所示)。 图1-1 ArrayList vs LinkedList add方法性能 ArrayList:最大耗时304毫秒,最小耗时18毫秒,平均耗时83.2 毫秒。 LinkedList:最大耗时455毫秒,最小耗时21毫秒,平均耗时104 毫秒。 乍一看ArrayList的add方法性能要好于LinkedList的add方法,事 实上,ArrayList的随机读写性能确实要好于LinkedList(尤其是在 ArrayList不进行内部扩容数组复制的情况下),LinkedList由于链表
The above is a preview of the first 20 pages. Register to read the complete e-book.
Comments 0
Loading comments...
Reply to Comment
Edit Comment