Java并发编程实践

合集下载

java多线程实际应用案例

java多线程实际应用案例

java多线程实际应用案例Java多线程是一种并发编程的方式,可以使程序同时执行多个任务,提高程序的执行效率和响应速度。

下面列举了十个Java多线程实际应用案例。

1. 电商网站订单处理:在一个电商网站中,订单的处理是一个非常繁琐且耗时的工作,可以使用多线程实现订单的并发处理,提高订单处理的效率。

2. 聊天软件消息发送:在聊天软件中,用户发送消息是一个频繁的操作,可以使用多线程实现消息的并发发送,提高用户体验。

3. 数据库读写操作:在数据库的读写操作中,读操作可以使用多线程并发执行,提高数据的读取速度;写操作可以使用多线程并发执行,提高数据的写入速度。

4. 图像处理:在图像处理中,可以使用多线程实现图像的并行处理,提高图像处理的速度。

5. 视频编解码:在视频编解码中,可以使用多线程实现视频的并行编解码,提高视频的处理速度。

6. 网络爬虫:在网络爬虫中,可以使用多线程实现并发的爬取网页数据,提高爬虫的效率。

7. 游戏开发:在游戏开发中,可以使用多线程实现游戏的并行处理,提高游戏的运行速度和响应速度。

8. 大数据处理:在大数据处理中,可以使用多线程实现并发的数据处理,提高大数据处理的效率。

9. 并发服务器:在服务器开发中,可以使用多线程实现并发的请求处理,提高服务器的并发能力。

10. 并发任务调度:在任务调度中,可以使用多线程实现并发的任务执行,提高任务的执行效率。

在实际应用中,多线程不仅可以提高程序的执行效率和响应速度,还可以充分利用多核处理器的优势,实现并行计算和并发处理。

然而,多线程编程也面临着诸多挑战,如线程安全、死锁、资源竞争等问题,需要设计合理的线程同步和互斥机制,确保程序的正确性和稳定性。

因此,在使用多线程编程时,需要仔细考虑线程间的依赖关系和数据共享问题,合理规划线程的数量和调度策略,确保多线程程序的正确性和性能。

Java并发编程实践-电子书-01章

Java并发编程实践-电子书-01章

第一章Java并发编程实践基础第一章Java并发编程实践基础 (1)1.1 进程与线程 (2)1.1.1 进程 (2)1.1.2 线程 (6)1.2 创建多线程 (7)1.2.1 继承Thread 创建线程 (8)1.2.2 实现Runnable 接口创建线程 (8)1.2.3 线程池 (9)1.3 线程的基本控制 (12)1.3.1 使用Sleep 暂停执行 (13)1.3.2 使用join 等待另外一个线程结束 (13)1.3.3 使用中断(Interrupt)取消线程 (15)1.3.4 使用Stop 终止线程 (18)1.3.5 结束程序的执行 (19)1.4 并发编程实践简述 (19)参考文献: (20)1.1进程与线程进程和线程是两个既有关系,又有重大区别的计算机概念,本届首先回顾一下进程和线程的基本概念,然后讲解一下他们的区别,最后是Java 线程概念模型。

1.1.1进程讲解进程的概念时,首先会提到与之相关的另一个概念:程序。

首先介绍程序的概念,然后引入进程。

1.1.1.1程序与资源共享1.程序的封闭性与可再现性在程序设计中,程序员习惯于用顺序方式编制程序。

例如,一个比较典型的顺序程序是:先从某一外部设备(例如磁盘)上输入数据,随之一步一步进行计算,最后将计算结果输出。

计算机中的这种程序活动有如下几个特点:(1)一个程序在机器中运行时独占全机资源,因此除了初始状态外,只有程序本身规定的动作才能改变这些资源的状态。

(2)机器严格地顺序执行程序规定的动作。

每个动作都必须在前一动作结束后才能开始,除了人为干预造成机器暂时停顿外,前一动作的结束就意味着后一动作的开始。

程序和机器执行程序的严格一一对应。

(3)程序的执行结果与它的运行速度无关。

也就是说,处理机在执行程序两个动作之间的停顿不会影响程序的执行结果。

上述特点概况起来就是程序的封闭性和可再现性。

所谓封闭性指的是程序一旦开始运行,其计算结果就只取决于程序本身,除了人为地改变机器的运行状态或机器故障以外,没有其它因素能够对程序的运行过程施加影响。

Java定时任务Quartz(三)——并发

Java定时任务Quartz(三)——并发

Java定时任务Quartz(三)——并发1 前⾔根据 Quartz 的设计,⼀个 Job 可以绑定多个 Trigger,必然会遇到并发的问题。

2 并发2.1 复现让我们编写⼀个并发的例⼦:1/**2 * @author pancc3 * @version 1.04*/5public class AcceptConcurrentDemo {67public static void main(String[] args) throws SchedulerException, InterruptedException {8 JobDetail detail = JobBuilder.newJob(AcceptConcurrentJob.class)9 .withIdentity("detail", "group0")10 .build();111213 Trigger trigger = TriggerBuilder.newTrigger()14 .withIdentity("ben_trigger")15 .usingJobData("name", "ben")16 .startNow()17 .build();1819 Trigger triggers = TriggerBuilder.newTrigger()20 .withIdentity("mike_trigger")21 .usingJobData("name", "mike")22 .forJob("detail", "group0")23 .startNow()24 .build();252627 Scheduler scheduler = new StdSchedulerFactory().getScheduler();2829 scheduler.start();30 scheduler.scheduleJob(detail, trigger);31 scheduler.scheduleJob(triggers);32/*33 * 6 秒钟后关闭34*/35 Thread.sleep(6_000);36 scheduler.shutdown();37 }3839 @Data40public static class AcceptConcurrentJob implements Job {41private String name;4243 @Override44public void execute(JobExecutionContext context) {45try {46 System.out.printf("i am %s \n", name);47 Thread.sleep(2_000);48 } catch (InterruptedException e) {49 e.printStackTrace();50 }51 }52 }53 }请注意上边的 Details 的 Identity ,设置为 group0.detail,同时我们创建了两个 Trigger,第⼆个 trigger 在创建的时候通过指定 Identity 绑定到了⽬标 Job,接着提交这个 Job,与两个 Trigger ,可以看到两个触发器同时出发了 Job 的 execute ⽅法上边的代码也可以简化为以下形式:1/**2 * @author pancc3 * @version 1.04*/5public class AcceptConcurrentDemo {67public static void main(String[] args) throws SchedulerException, InterruptedException {8 JobDetail detail = JobBuilder.newJob(AcceptConcurrentJob.class)9 .withIdentity("detail", "group0")10 .build();111213 Trigger trigger = TriggerBuilder.newTrigger()14 .withIdentity("ben_trigger")15 .usingJobData("name", "ben")16 .startNow()17 .build();1819 Trigger triggers = TriggerBuilder.newTrigger()20 .withIdentity("mike_trigger")21 .usingJobData("name", "mike")22 .startNow()23 .build();242526 Scheduler scheduler = new StdSchedulerFactory().getScheduler();2728 scheduler.start();29 scheduler.scheduleJob(detail, Sets.newHashSet(trigger,triggers),true);30/*31 * 6 秒钟后关闭32*/33 Thread.sleep(6_000);34 scheduler.shutdown();35 }3637 @Data38public static class AcceptConcurrentJob implements Job {39private String name;4041 @Override42public void execute(JobExecutionContext context) {43try {44 System.out.printf("i am %s \n", name);45 Thread.sleep(2_000);46 } catch (InterruptedException e) {47 e.printStackTrace();48 }49 }50 }51 }2.2 避免并发为了避免并发,我们可以使⽤官⽅提供的注解 @DisallowConcurrentExecution,通过在类上增加这个注解,我们可以观察到第⼆个 trigger 进⾏了排队处理: 1/**2 * @author pancc3 * @version 1.04*/5public class RejectConcurrentDemo {67public static void main(String[] args) throws SchedulerException, InterruptedException {8 JobDetail detail = JobBuilder.newJob(RejectConcurrentJob.class)9 .withIdentity("detail", "group0")10 .build();111213 Trigger trigger = TriggerBuilder.newTrigger()14 .withIdentity("ben_trigger")15 .usingJobData("name", "ben")16 .startNow()17 .build();1819 Trigger triggers = TriggerBuilder.newTrigger()20 .withIdentity("mike_trigger")21 .usingJobData("name", "mike")22 .forJob("detail", "group0")23 .startNow()24 .build();252627 Scheduler scheduler = new StdSchedulerFactory().getScheduler();2829 scheduler.start();30 scheduler.scheduleJob(detail, trigger);31 scheduler.scheduleJob(triggers);32/*33 * 6 秒钟后关闭34*/35 Thread.sleep(6_000);36 scheduler.shutdown();37 }383940 @DisallowConcurrentExecution41 @Data42public static class RejectConcurrentJob implements Job {43private String name;4445 @Override46public void execute(JobExecutionContext context) {47try {48 System.out.printf("i am %s \n", name);49 Thread.sleep(2_000);50 } catch (InterruptedException e) {51 e.printStackTrace();52 }53 }54 }55 }3 避免并发的原理探索让我们找到 JobStore 的实现类,在这⾥是 RAMJobStore,点进去⽅法 org.quartz.simpl.RAMJobStore#acquireNextTriggers,可以看到这个⽅法的某个块:通过对 Job 类上的是否存在 DisallowConcurrentExecution 注解,如果存在,表⽰拒绝并发执⾏ execute ⽅法。

程序并发执行实验报告

程序并发执行实验报告

一、实验目的1. 理解并发执行的概念和原理。

2. 掌握多线程编程的基本方法。

3. 学会使用同步机制解决并发编程中的竞争条件。

4. 分析并发程序的性能和效率。

二、实验环境1. 操作系统:Windows 102. 编程语言:Java3. 开发工具:Eclipse三、实验内容1. 创建一个简单的并发程序,实现两个线程同时执行。

2. 使用同步机制解决并发程序中的竞争条件。

3. 分析并发程序的性能和效率。

四、实验步骤1. 创建一个简单的并发程序(1)创建一个名为ConcurrentTest的类,该类继承自Thread类。

(2)在ConcurrentTest类的run方法中,打印出当前线程的名字。

(3)在主函数中,创建两个ConcurrentTest对象,分别命名为thread1和thread2。

(4)启动thread1和thread2线程。

(5)等待thread1和thread2线程执行完毕。

2. 使用同步机制解决并发程序中的竞争条件(1)创建一个名为Counter的类,该类包含一个私有变量count和一个静态同步方法add。

(2)在add方法中,增加count变量的值。

(3)在主函数中,创建一个Counter对象counter。

(4)创建两个线程,分别调用counter对象的add方法。

(5)启动两个线程,并等待它们执行完毕。

3. 分析并发程序的性能和效率(1)在主函数中,记录两个线程开始执行的时间。

(2)在主函数中,记录两个线程执行完毕的时间。

(3)计算两个线程执行所需的时间差。

五、实验结果与分析1. 实验结果(1)简单的并发程序在控制台中,可以看到thread1和thread2线程交替打印出它们的名字。

(2)使用同步机制解决竞争条件在控制台中,可以看到Counter对象的count变量值正确地增加了。

(3)分析并发程序的性能和效率thread1和thread2线程执行所需的时间差为0.01秒。

2. 实验分析(1)简单的并发程序通过创建两个线程,实现了两个任务同时执行。

java实训总结8篇

java实训总结8篇

java实训总结8篇第1篇示例:Java实训是计算机科学领域必不可少的一部分,通过实训学习,可以帮助学生们更好地理解Java编程语言的应用和技巧。

在接受Java 实训的过程中,我收获颇丰,不仅提升了自己的编程能力,还学到了很多实践经验和团队协作的重要性。

在实训过程中,我们主要学习了Java基础知识,包括语法、数据类型、操作符、流程控制等等。

通过实际操作和编程练习,我们逐渐掌握了Java编程的技巧和方法。

在课堂上,老师会通过实例讲解和演示,让我们更直观地理解程序的运行原理和逻辑。

我们还要完成一些编程作业和小项目,这不仅锻炼了我们的编程能力,也提高了我们的解决问题的能力。

在团队项目中,我们体会到了团队协作的重要性。

在一个项目中,每个人都有自己的任务和责任,只有团结协作,才能顺利完成项目。

我们要相互配合,合理分工,共同解决遇到的问题,不断完善和改进项目。

通过项目实践,我们不仅学到了团队合作的技巧,还体会到了团队协作的意义和价值。

在实训中,我们还学习了一些Java框架和工具,如Spring、MyBatis等。

这些框架和工具可以帮助我们更高效地开发Java项目,提高代码的质量和性能。

通过学习和实践,我们更加深入地了解了Java编程的应用领域和发展趋势,为将来的工作打下了坚实的基础。

Java实训是一次宝贵的学习经历,让我们更加深入地了解了Java 编程语言的应用和技巧,提升了我们的编程能力和团队协作能力。

通过不断地实践和学习,我们能够更好地应对未来的挑战和机遇,成为优秀的Java程序员和团队合作者。

希望能够将学到的知识应用到实际工作中,不断进步和提高自己的专业技能。

【注:本文纯属虚构,如有雷同,纯属巧合。

】第2篇示例:本次Java实训总结,我从基础知识的学习和实践中获益良多。

通过训练,我深入了解了Java编程语言的特点、编程规范以及常见的应用场景和技巧,对于程序设计和开发也有了更深刻的理解。

在实训过程中,我系统地学习了Java语言的基础知识,例如数据类型、运算符、控制流程、数组、面向对象等概念。

多线程并发实验报告心得

多线程并发实验报告心得

多线程并发实验报告心得
一、实验介绍
本次实验是多线程并发实验,旨在通过编写多线程程序,掌握多线程编程的基本原理和技巧,并了解并发程序的运行机制。

二、实验环境
本次实验使用Java语言,在Eclipse开发环境下完成。

三、实验过程
1. 熟悉多线程编程的基本原理和技巧,包括线程的创建、启动、休眠等操作;
2. 编写多线程程序,模拟多个人同时购买火车票的场景;
3. 在程序中设置同步锁,保证只有一个人能够购买到票;
4. 运行程序,观察并发程序的运行机制。

四、实验结果
经过多次测试和调试,我们成功地编写出了一个模拟购票系统的多线程程序。

在运行过程中,我们观察到不同线程之间存在竞争关系,并且通过设置同步锁,保证了只有一个人能够成功购买到票。

五、心得体会
通过本次实验,我深刻地认识到了并发编程的重要性。

在日常开发中,很多应用都需要支持并发访问,在不加注意的情况下很容易出现资源
竞争等问题。

因此,在进行并发编程时,我们必须充分考虑并发访问
的可能性,并采取相应的措施来保证程序的正确性和稳定性。

同时,我也认识到了多线程编程的复杂性。

在编写多线程程序时,我
们需要考虑线程之间的协作关系、同步锁的设置、异常处理等问题,
这些都需要我们具备较高的编程技能和经验。

因此,在进行多线程编
程时,我们需要仔细思考,并且不断地积累经验。

最后,我认为本次实验对我的编程能力提升有很大帮助。

通过实践操作,我深入了解了多线程并发编程的原理和技巧,并且掌握了一些实
用的技巧和方法。

相信这些知识和经验将对我的日常开发工作产生积
极影响。

实战Java高并发程序设计

实战Java高并发程序设计
4.1 有助于提高“锁”性能的几点建议 139 4.1.1 减小锁持有时间 139 4.1.2 减小锁粒度 140 4.1.3 读写分离锁来替换独占锁 142 4.1.4 锁分离 142 4.1.5 锁粗化 144
4.2 Java 虚拟机对锁优化所做的努力 146 4.2.1 锁偏向 146 4.2.2 轻量级锁 146 4.2.3 自旋锁 146 4.2.4 锁消除 146
3.1 多线程的团队协作:同步控制 70 3.1.1 synchronized 的功能扩展:重入锁 71 3.1.2 重入锁的好搭档:Condition 条件 80 3.1.3 允许多个线程同时访问:信号量(Semaphore) 83 3.1.4 ReadWriteLock 读写锁 85 3.1.5 倒计时器:CountDownLatch 87 3.1.6 循环栅栏:CyclicBarrier 89 3.1.7 线程阻塞工具类:LockSupport 92
3.2 线程复用:线程池 95 3.2.1 什么是线程池 96 3.2.2 不要重复发明轮子:JDK 对线程池的支持 97 3.2.3 刨根究底:核心线程池的内部实现 102 3.2.4 超负载了怎么办:拒绝策略 106 3.2.5 自定义线程创建:ThreadFactory 109 3.2.6 我的应用我做主:扩展线程池 110 3.2.7 合理的选择:优化线程池线程数量 112 3.2.8 堆栈去哪里了:在线程池中寻找堆栈 113 3.2.9 分而治之:Fork/Join 框架 117
V
1.3.5 无等待(Wait-Free) 13 1.4 有关并行的两个重要定律 13
1.4.1 Amdahl 定律 13 1.4.2 Gustafson 定律 16 1.4.3 Amdahl 定律和 Gustafson 定律是否相互矛盾 16 1.5 回到 Java:JMM 17 1.5.1 原子性(Atomicity) 18 1.5.2 可见性(Visibility) 20 1.5.3 有序性(Ordering) 22 1.5.4 哪些指令不能重排:Happen-Before 规则 27 1.6 参考文献 27 第 2 章 Java 并行程序基础 ..............................................................................................................................29 2.1 有关线程你必须知道的事 29 2.2 初始线程:线程的基本操作 32 2.2.1 新建线程 32 2.2.2 终止线程 34 2.2.3 线程中断 38 2.2.4 等待(wait)和通知(notify) 41 2.2.5 挂起(suspend)和继续执行(resume)线程 44 2.2.6 等待线程结束(join)和谦让(yield) 48 2.3 volatile 与 Java 内存模型(JMM)50 2.4 分门别类的管理:线程组 52 2.5 驻守后台:守护线程(Daemon) 54 2.6 先干重要的事:线程优先级 55 2.7 线程安全的概念与 synchronized 57

如何在Java中进行并发计算和分布式系统的优化设计

如何在Java中进行并发计算和分布式系统的优化设计

如何在Java中进行并发计算和分布式系统的优化设计并发计算是指多个任务在同一时间段内同时执行的计算方式。

而分布式系统是指将一个计算机系统分布在不同的物理位置上,通过网络互联,形成一个整体的计算系统。

在Java中,可以使用多线程技术来实现并发计算,同时也可以使用分布式框架来优化分布式系统的设计。

1.并发计算的优化设计:在Java中,可以通过以下几种方式来优化并发计算的设计:1.1使用线程池:线程池是一个管理线程的工具,可以重用已创建的线程,有效地管理线程的创建和销毁。

通过使用线程池,可以避免频繁地创建和销毁线程所带来的开销,并且可以控制同时执行的线程数量,避免系统资源被过度占用。

1.2使用锁机制:Java提供了synchronized关键字和Lock接口来实现锁机制,可以保证多个线程访问共享资源的互斥性,避免数据竞争和不一致性。

在多线程环境下,通过合理的锁机制设计,可以提高并发计算的效率和准确性。

1.3使用并发容器:Java提供了一系列的并发容器,如ConcurrentHashMap、ConcurrentLinkedQueue等,这些容器在多线程环境下具有较高的并发性能。

通过使用并发容器,可以避免手动实现线程安全的数据结构,减少错误和并发问题的发生。

1.4使用无锁算法:无锁算法是一种高效的并发计算方式,通过使用原子操作或CAS(Compare and Swap)指令来实现多个线程对共享资源的并发操作,避免了锁机制带来的性能损耗。

在Java中,可以使用Atomic类或java.util.concurrent.atomic包下的原子类来实现无锁算法。

1.5使用并行流和并行算法:Java 8引入了Stream API和并行流(Parallel Stream),通过将计算任务分解为多个子任务,然后并行执行,可以利用多核处理器的性能优势,提高计算速度。

同时,还可以使用Java 8提供的并行算法,如并行排序、并行归约等,进一步提高并发计算的效率。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
9chunk
chunk1
1.1.3.4
让所有这个类下面的对象都同步的时候,也就是让所有这个类下面的对象共用同一把锁的时候,我们可以在区块中锁定类常量的方式进行。例如:
通过锁定lock对象,我们可以实现对这个类所有对象的同步。切记synchronized锁定的是对象,对象不同就不会同步。例如:
两个方法就不会同步一个锁定的是lock一个锁定的是类对象。
1.1.2
Java内存模型要求,非volatile类型的64位数值变量(double和long),JVM允许将64位的读操作和写操作分解为两个32位的操作。
那么在多线程的环境中,如果要读取非volatile类型的double、隆就有可能会读取到某个值的高32位和另一个值的低32位组成的一个数值。
但目前各种平台的商用虚拟机几乎都把64位数据的读写操作作为原子操作来对待。
volatile的第二种特性是禁止指令重排序。
Java内存模型对volatile变量的特殊规则如下:
在线程工作内存中,每次使用volatile变量,都必须先从主内存刷新最新的值,用于保证能及时看见其他线程对volatile变量所做的修改
每次修改volatile变量后都应立即同步到主内存中,用于保证其他线程可以看到对volatile变量所做的修改
3.除了在方法上用synchronized关键字外,也可以在方法内部的某个区块中用synchronized表示只对这个区块中的资源进行同步访问,例如synchronized(this){/**区块**/}的作用域就是当前对象。
1.1.3.1
运行结果是:chunk对象与chunk1对象锁互不干扰。
chunk1
9chunk
1.1.3.2
结果与上面一样,也是chunk与chunk1互不干扰
chunk1
9chunk
1.1.3.3
注意这段代码中的chunk与chunk1是互不干扰的,因为他们一个是static一个是非static方法。执行结果是:
chunk1
9chunk
这段代码中的chunk与chunk1就可以进行同步操作了。因为他们的锁是同一个锁,执行结果是:
在Java5.0中,Integer.toString()由之前的ThreadLocal对象保存12字节大小的缓冲区变成了每次调用时分配一个新的缓冲区,对于像临时缓冲区这样简单的对象,除非频繁操作否则ThreadLocal没有性能优势。
概念上,可以讲ThreadLocal<T>看成是map(Thread,T)对象,其中保存了特定于该线程的值,但事实并非如此,特定于线程的值保存在Thread对象中。
volatile修饰的变量需保证代码的执行顺序与程序的顺序相同
1.1.5
volatile的字面意思就是“易变的”,其意思就是告诉Java的内存模型存储在寄存器中存放的当前变量是不确定的,需要从主存中读取,修改完成后也要立即将变量写入到主存中去。而synchronized则是锁定的当前变量,只有当前线程才可以访问该变量,其他线程将被阻塞。
volatile只能由于变量级别,而synchronized却可以用于变量和方法级别
volatile仅能保证变量的修改可见性不能保证变量的修改原子性,而synchronized既能保证变量的修改可见性也能保证变量的修改原子性
volatile不会造成线程堵塞,而synchronized可能会造成线程阻塞
}
}
}
用工厂方法可以防止this引用逸出
1.3
线程封闭:只在单线程内访问数据,这种技术称为线程封闭
当对象被封闭在一个线程中,自动成为线程安全的,即使被封闭的对象本身不是线程安全的。如JDBC连接池,Connection对象并不是线程安全的,但是大多数请求(Servlet请求或者EJB调用)都是由单个线Leabharlann 采用同步的方式来处理,因封闭而安全。
ReentrantLock拥有synchronized相同的并发性和语义,此外还多了锁投票、定时锁等待和中断锁等待。例如线程A和线程B都要获得对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定,如果使用synchronized,如果A不释放,B将一直等待下去无法中断。如果使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时候以后中断等待,而去干别的事情。
}
private class EscapeRunnable implements Runnable{
public void run(){
//通过ThisEscape.this就可以引用外围类对象,但是此时外围类对象还没有构造完成,即发生了外围类的this引用的逸出。所以在构造函数中创建Thread对象后不要启动Thread。可以提供一个start或者init方法负责启动线程。
每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且ThreadLocal实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
1.在某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象其他的synchronized方法(这个对象还有其他的synchronized方法,如果其中一个线程访问了其中一个synchronized方法,那么其他线程将不能访问此对象另外的synchronized方法)。但不同的对象实例间的synchronized方法是相互独立的,也就是说其他线程照样可以访问相同类的另一个对象实例的synchronized方法。
volatile标记的变量不会被编译器优化,而synchronized标记的变量可以被编译器优化
1.1.6
在代码层面上来说,synchronized类似面向对象,它可以修饰变量、方法、类、对象等。而Lock却像是面向过程,在需要的时候获取锁,结束的时候释放锁(一般是在finally中释放)。
从性能上来说,在低并发的情况下synchronized要比Lock性能好,在高并发的情况下,Lock要比synchronized的性能好很多。
1.1.3
加锁的含义不仅仅局限于互斥行为,还包括内存可见性。为了确保所有线程都能看到共享变量的最新值,所有执行读操作或者写操作的线程都必须在同一个锁上同步。
同步代码块的锁就是方法调用所在的对象,静态synchronized方法以Class对象作为锁。
synchronized可以用于实例变量、对象引用、static方法、类名称字面常量。
原则:为防止逸出,对象必须要被完全构造完后,才可以被发布(最好的解决办法是采用同步)
this逸出是指构造函数返回之前其他线程就持有该对象的引用,this逸出经常发生在构造函数中启动线程和注册监听器。如
public class ThisEscape{
public ThisEscape(){
new Thread(new EscapeRunnable()).start();
synchronized是在JVM层面实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM将自动释放锁。Lock则不行,因为Lock通过代码实现它必须在finally中释放锁。synchronized在生成线程转储时生成文件对开发人员找出死锁原因很有帮助,而Lock对于查找死锁原因将很困难,这个问题在Java6中已经得到解决,它提供了一个管理和调试的接口,锁可以通过这个接口进行注册,并通过其他管理和调试接口,从线程转储中得到ReentrantLock的加锁信息。
1.4
当满足以下条件时,对象才是不可变的:
对象创建后其状态就不能再改变
对象的所有域都是final类型
对象是正确创建的(在对象的创建期间,this引用没有逸出)
特别说明:不可变对象的域并未全部声明为final类型。如String会惰性地(lazily)的计算哈希值:当第一次调用hashcode()时,String计算哈希值,并将它缓存在一个非final域中。这个域有一个非默认的值,在每次计算中得得到相同的结果。
例如:如果在线程内部发布了局部变量(一个collection对象)的引用或者将该collection对象中的数据发布,那么封闭性将会被破坏,导致collection对象的逸出
1.3.3
ThreadLocal对象通常用于防止对可变的单实例变量(Singleton)或全局变量进行共享。
当某个频繁执行的操作需要一个临时对象,例如一个缓冲区,而同时又希望避免在每次执行时都重新分配该临时对象。就可以使用ThreadLocal。但是除非这个操作的执行频率非常高,或者分配操作的开销非常高,否则ThreadLocal不能带来性能的提升。
volatile的使用情况如下:
运算结果不依赖于变量的当前值,或者能够确保只有单一线程修改变量的值
变量不需要与其他的状态变量共同参与不变形约束
例如:当需要检查某个状态标记以判断是否退出循环的时候可以考虑采用volatile,加锁机制既可以确保可见性又可以确保原子性,而volatile变量只能确保可见性。
Synchronized获取锁和释放锁这样的行为是成对出现的,而ReentrantLock却不是这样的,举例来说在一个链表结构中,可以将ReentrantLock加到链表结构的每个节点上来减少锁的粒度,从而允许不同的线程操作链表的不同部分。
1.2
发布对象:指的是使它能够被当前范围之外的代码所使用,例如将一个指向该对象的引用保存到其他代码可以访问的地方,或者在某一个非私有的方法中返回该引用,或者将引用传递到其他类的方法中。
相关文档
最新文档