在并发编程中经常会碰到多个执行线程共享资源的问题。例如多个线程同时读写文件,共用数据库连接,全局的计数器等。如果不处理好多线程之间的同步问题很容易引起状态不一致或者其他的错误。
同步不仅可以阻止一个线程看到对象处于不一致的状态,它还可以保证进入同步方法或者块的每个线程,都看到由同一锁保护的之前所有的修改结果。处理同步的关键就是要正确的识别临界条件(critical section),即多线程访问/修改共享资源的代码块。
关键字synchronized可以保证同一时刻,只有一个线程可以执行某个方法或者某个代码块。 此外Java语言规范保证读写一个变量是原子的,除非long或者double.虽然语言规范保证了线程在读取原子数据的时候,不会看到任意的数值,但是并不保证一个线程写入的值对于另一个线程是可见的,线程间的通信,同步是必要的。
synchronized同步方法:
我们可以把synchronized关键字放在方法前,保证同时只有一个线程执行该方法。需要注意的是如果一个类的静态方法和实例方法都有synchronized,那么同意时刻允许一个线程访问静态方法,另一个线程访问实例方法。例如:
private static synchronized void stopRequested(){ stopRequest = true; }
注意确保synchronized 方法仅仅是非常短的修改或者读取共享资源,否则会引起性能问题,因为synchronized本质上是互斥的。
synchronized同步块:
synchronized (this) { // Java code }
同步块可以让我们仅仅同步临界段,其余部分可以并行。 对于相互独立的共享资源,可以用不同的锁同步。例如同时售两个电影院的票:
public class Cinema { private long vacanciesCinema1; private long vacanciesCinema2; private final Object controlCinema1, controlCinema2; public Cinema() { controlCinema1 = new Object(); controlCinema2 = new Object(); vacanciesCinema1 = 20; vacanciesCinema2 = 20; } public boolean sellTickets1(int number) { synchronized (controlCinema1) { if (number < vacanciesCinema1) { vacanciesCinema1 -= number; return true; } else { return false; } } } public boolean sellTickets2(int number) { synchronized (controlCinema2) { if (number < vacanciesCinema2) { vacanciesCinema2 -= number; return true; } else { return false; } } } }
虽然读写primitive类型是原子的,但是如果线程之间不同步,还是会引起数据不一致问题,看下面这个例子:
public class TestStop { private static boolean stopRequest; public static void main(String[]args) throws InterruptedException{ Thread t = new Thread( new Runnable(){ public void run(){ int i = 0; while(!stopRequest){ i++; } } }); t.start(); TimeUnit.SECONDS.sleep(2); stopRequest = true; } }
这段代码有时候无法停止,因为子线程没看到主线程对stopRequest的改变。解决的办法是加上对共享变量的同步访问:
public class TestStop { private static boolean stopRequest; private static synchronized void stopRequested(){ stopRequest = true; } private static synchronized boolean getStopRequest(){ return stopRequest; } public static void main(String[]args) throws InterruptedException{ Thread t = new Thread( new Runnable(){ public void run(){ int i = 0; while(!getStopRequest()){ i++; } } }); t.start(); TimeUnit.SECONDS.sleep(2); stopRequested(); } }
如果读写都没有同步,同步就没有效果。 针对此例,还可以用volatile,去掉同步。
在后续章节中,我们将介绍更多关于synchronize及Lock的内容。
相关推荐
微观经济学讲义-第13章博弈论
博弈论与信息经济学讲义-.ppt
1. **基本概念**:博弈论的基本元素包括参与者(玩家)、策略集、支付函数和博弈结构。每个参与者都有自己的目标,通过选择不同的策略来追求最大化利益。 2. **零和博弈与非零和博弈**:零和博弈中,一方的收益必然...
管理经济学讲义-之博弈论篇.ppt
复旦大学本科讲义-微观经济学讲义第13章 博弈论与竞争策略.pptx
本项目聚焦于“五子棋”的Java实现,通过博弈算法来实现智能对战功能。下面将详细介绍五子棋的基本规则、Java编程语言在游戏开发中的应用以及博弈算法的相关知识。 五子棋是一种双人对弈的策略型棋类游戏,双方轮流...
1. **纳什均衡**:纳什均衡是指在给定其他参与者策略不变的情况下,任何参与者都无法通过改变自己的策略来获得更好的结果。这种策略组合由所有参与者最优策略组成,一旦形成,没有任何参与者有动机单方面改变策略。 ...
五子棋游戏想必大家都非常熟悉,游戏规则十分简单。...Java、Python、Node.js、Spring Boot、Django、Express、MySQL、PostgreSQL、MongoDB、React、Angular、Vue、Bootstrap、Material-UI、Redis、Docker、Kubernetes
《伟大的博弈---华尔街金融帝国的崛起》.pdf
跨境电商贸易便利化监管的演化博弈分析--以前景理论为研究进路.pdf
人机博弈。PDF中文版。。。。。。。。。。。。。。。。。。。。。。。。。
七所大学的博弈论讲义,包括哈佛大学.卡内基梅隆大学.芝加哥大学.加利福尼亚大学(圣. 迭戈校区).加利福尼亚
多站融合论文仿真-遗传算法-主从博弈_MasterSlaveGame-GA-SmartGrid
哈佛大学的博弈论讲义是这个领域的权威资料之一,深受学者和学生们的喜爱。本讲义深入浅出地介绍了博弈论的基本概念、理论与应用,帮助读者理解在竞争与合作中的决策制定。 首先,我们要理解博弈论的核心概念——...
《用脑拿订单:销售中的全脑博弈》--大客户销售.pptx
《用脑拿订单:销售中的全脑博弈》--大客户销售.ppt
利率债中期投资策略:一致预期下的博弈-0709-民生证券-55页.pdf
经济博弈论基础-第五章、动态贝叶斯博弈 经济博弈论基础是研究经济领域中博弈现象的理论基础,它的研究对象是经济主体之间的博弈行为。经济博弈论基础的研究内容包括策略型博弈、扩展型博弈、贝叶斯博弈等几个方面...
五子棋博弈的实现-todo (1) (1) (1).ipynb