Java多线程5:synchronized锁方法块

synchronized同步代码块

用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法执行一个较长时间的任务,那么B线程必须等待比较长的时间。这种情况下可以尝试使用synchronized同步语句块来解决问题。看一下例子:

这个实验可以得出以下两个结论:

1、当A线程访问对象的synchronized代码块的时候,B线程依然可以访问对象方法中其余非synchronized块的部分,第一部分的执行结果证明了这一点

2、当A线程进入对象的synchronized代码块的时候,B线程如果要访问这段synchronized块,那么访问将会被阻塞,第二部分的执行结果证明了这一点

所以,从执行效率的角度考虑,有时候我们未必要把整个方法都加上synchronized,而是可以采取synchronized块的方式,对会引起线程安全问题的那一部分代码进行synchronized就可以了。

运行结果,分两部分来看:

两个synchronized块之间具有互斥性

如果线程1访问了一个对象A方法的synchronized块,那么线程B对同一对象B方法的synchronized块的访问将被阻塞,写个例子来证明一下:

看到对于serviceMethodB()方法synchronized块的访问必须等到对于serviceMethodA()方法synchronized块的访问结束之后。那其实这个例子,我们也可以得出一个结论:synchronized块获得的是一个对象锁,换句话说,synchronized块锁定的是整个对象

synchronized块和synchronized方法

既然上面得到了一个结论synchronized块获得的是对象锁,那么如果线程1访问了一个对象方法A的synchronized块,线程2对于同一对象同步方法B的访问应该是会被阻塞的,因为线程2访问同一对象的同步方法B的时候将会尝试去获取这个对象的对象锁,但这个锁却在线程1这里。写一个例子证明一下这个结论:

证明了我们的结论。为了进一步完善这个结论,把"otherMethod()"方法的synchronized去掉再看一下运行结果:

"otherMethod()"方法和"doLongTask()"方法中的synchronized块异步执行了

将任意对象作为对象监视器

总结一下前面的内容:

1、synchronized同步方法

(1)对其他synchronized同步方法或synchronized(this)同步代码块呈阻塞状态

(2)同一时间只有一个线程可以执行synchronized同步方法中的代码

2、synchronized同步代码块

(1)对其他synchronized同步方法或synchronized(this)同步代码块呈阻塞状态

(2)同一时间只有一个线程可以执行synchronized(this)同步代码块中的代码

前面都使用synchronized(this)的格式来同步代码块,其实Java还支持对"任意对象"作为对象监视器来实现同步的功能。这个"任意对象"大多数是实例变量方法的参数,使用格式为synchronized(非this对象)。看一下将任意对象作为对象监视器的使用例子:

这个例子证明了:多个线程持有"对象监视器"为同一个对象的前提下,同一时间只能有一个线程可以执行synchronized(非this对象x)代码块中的代码

锁非this对象具有一定的优点:如果在一个类中有很多synchronized方法,这时虽然能实现同步,但会受到阻塞,从而影响效率。但如果同步代码块锁的是非this对象,则synchronized(非this对象x)代码块中的程序与同步方法是异步的,不与其他锁this同步方法争抢this锁,大大提高了运行效率。

注意一下"private String anyString = new String();"这句话,现在它是一个全局对象,因此监视的是同一个对象。如果移到try里面,那么对象的监视器就不是同一个了,调用的时候自然是异步调用,可以自己试一下。

最后提一点,synchronized(非this对象x),这个对象如果是实例变量的话,指的是对象的引用,只要对象的引用不变,即使改变了对象的属性,运行结果依然是同步的

细化synchronized(非this对象x)的三个结论

synchronized(非this对象x)格式的写法是将x对象本身作为对象监视器,有三个结论得出:

1、当多个线程同时执行synchronized(x){}同步代码块时呈同步效果

2、当其他线程执行x对象中的synchronized同步方法时呈同步效果

3、当其他线程执行x对象方法中的synchronized(this)代码块时也呈同步效果

第一点很明显,第二点和第三点意思类似,无非一个是同步方法,一个是同步代码块罢了,举个例子验证一下第二点:

写两个线程分别调用"speedPrintString()"方法和"testMethod1(MyObject mo)"方法:

看到"speedPrintString()"方法必须等待"testMethod1(MyObject mo)"方法执行完毕才可以执行,没有办法异步执行,证明了第二点的结论。第三点的验证方法类似,就不写代码证明了。

时间: 2024-10-04 05:30:02

Java多线程5:synchronized锁方法块的相关文章

java 多线程9 : synchronized锁机制 之 代码块锁

synchronized同步代码块 用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法执行一个较长时间的任务,那么B线程必须等待比较长的时间.这种情况下可以尝试使用synchronized同步语句块来解决问题.看一下例子: 下面例子是优化后的例子 使用代码块锁,原先例子是方法锁,就是同步 必须要执行2个for  public class ThreadDomain18 { public void doLongTimeTask() throws Exception

java 多线程8 : synchronized锁机制 之 方法锁

脏读 一个常见的概念.在多线程中,难免会出现在多个线程中对同一个对象的实例变量或者全局静态变量进行并发访问的情况,如果不做正确的同步处理,那么产生的后果就是"脏读",也就是取到的数据其实是被更改过的.注意这里 局部变量是不存在脏读的情况 多线程线程实例变量非线程安全 看一段代码: public class ThreadDomain13 { private int num = 0; public void addNum(String userName) { try { if ("

synchronized锁方法块

http://www.cnblogs.com/xrq730/p/4851530.html synchronized同步代码块 用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法执行一个较长时间的任务,那么B线程必须等待比较长的时间.这种情况下可以尝试使用synchronized同步语句块来解决问题.看一下例子: public class ThreadDomain18 { public void doLongTimeTask() throws Exception

java基础知识回顾之java Thread类学习(五)--java多线程安全问题(锁)同步的前提

这里举个例子讲解,同步synchronized在什么地方加,以及同步的前提: * 1.必须要有两个以上的线程,才需要同步. * 2.必须是多个线程使用同一个锁. * 3.必须保证同步中只能有一个线程在运行,锁加在哪一块代码 那么我们要思考的地方有:1.知道我们写的哪些是多线程代码 2.明确共享数据 3.明确多线程运行的代码中哪些语句是操作共享数据的.. 4.要确保使用同一个锁. 下面的代码:需求:两个存户分别往银行存钱,每次村100块,分三次存完. class bank{ private int

java基础知识回顾之java Thread类学习(四)--java多线程安全问题(锁)

上一节售票系统中我们发现,打印出了错票,0,-1,出现了多线程安全问题.我们分析为什么会发生多线程安全问题? 看下面线程的主要代码: @Override public void run() { // TODO Auto-generated method stub while(true){ if(ticket > 0){//当线程0被调起的时候,当执行到这条判断语句的时候,线程1被调起抢了CPU资源,线程0进入冻结状态. try { Thread.sleep(100);//中断当前活跃的线程,或者

Java多线程-同步:synchronized 和线程通信:生产者消费者模式

大家伙周末愉快,小乐又来给大家献上技术大餐.上次是说到了Java多线程的创建和状态|乐字节,接下来,我们再来接着说Java多线程-同步:synchronized 和线程通信:生产者消费者模式. 一.同步:synchronized 多个线程同时访问一个对象,可能造成非线程安全,数据可能错误,所谓同步:就是控制多个线程同时访就是控制多线程操作同一个对象时,注意是同一个对象,数据的准确性, 确保数据安全,但是加入同步后因为需要等待,所以效率相对低下. 如:一个苹果,自己一个人去咬怎么都不会出问题,但是

Java多线程系列--“JUC锁”05之 非公平锁

获取非公平锁(基于JDK1.7.0_40) 非公平锁和公平锁在获取锁的方法上,流程是一样的:它们的区别主要表现在"尝试获取锁的机制不同".简单点说,"公平锁"在每次尝试获取锁时,都是采用公平策略(根据等待队列依次排序等待):而"非公平锁"在每次尝试获取锁时,都是采用的非公平策略(无视等待队列,直接尝试获取锁,如果锁是空闲的,即可获取状态,则获取锁).在前面的"Java多线程系列--"JUC锁"03之 公平锁(一)&q

Java多线程系列--“JUC锁”11之 Semaphore信号量的原理和示例

概要 本章,我们对JUC包中的信号量Semaphore进行学习.内容包括:Semaphore简介Semaphore数据结构Semaphore源码分析(基于JDK1.7.0_40)Semaphore示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3534050.html Semaphore简介 Semaphore是一个计数信号量,它的本质是一个"共享锁". 信号量维护了一个信号量许可集.线程可以通过调用acquire()来获取信号量的许可

Java多线程系列--“JUC锁”04之 公平锁(二)

前面一章,我们学习了"公平锁"获取锁的详细流程:这里,我们再来看看"公平锁"释放锁的过程."公平锁"的获取过程请参考"Java多线程系列–"JUC锁"03之 公平锁(一)",锁的使用示例请参考"Java多线程系列–"JUC锁"02之 互斥锁ReentrantLock". 注意(01)这里是以"公平锁"来进行说明.(02)关于本章的术语,如"