补充一个synchronized关键字的结论:

线程A先持有object对象的Lock锁,B线程可以以异步的方式调用object对象中的非synchronized类型的方法

A线程现持有object对象的Lock锁,B线程如果这个时候调用object对象中的synchronized类型的方法则需要等待,也就是同步

当线程A调用anyObject对象加入synchronized关键字的X方法时,A线程就获得了X方法所在对象的锁,所以其他线程必须等A线程执行完毕才可以调用X方法,而B线程如果调用声明了synchronize关键字的非X方法时,必须等A线程将X方法执行完,也就是释放对象锁之后才可以调用。这时A已经执行了一个完整的任务,也就是变量已经完成了变化,不存在脏读的基本环境。(X方法和非X方法均处在同一个类下面,是同一个对象的不同方法)

关键字synchronized取得的锁都是对象锁,而不是把一段代码或方法(函数)当作锁,所以在前面例子中,哪个线程先执行带synchronized关键字的方法,哪个线程就持有该方法所属对象的锁Lock,那么其他线程只能呈等待状态,前提是多个线程访问同一个对象

如果多个线程访问多个对象,则JVM会创建多个锁。会以异步的方式运行。

同步的单词为synchronized 异步的单词为asynchronized

当一个线程出现异常时,锁会自动释放。

同步不具有继承性,即:父类方法中加了synchronized关键字,子类调用父类的方法时,这个被继承来的方法不具备同步的特性。

public classMain {synchronized public voidserviceMethod() {try{

System.out.println("int main 下一步 sleep begin threadName="

+ Thread.currentThread().getName() + " time="

+System.currentTimeMillis());

Thread.sleep(5000);

System.out.println("int main 下一步 sleep end threadName="

+ Thread.currentThread().getName() + " time="

+System.currentTimeMillis());

}catch(InterruptedException e) {

e.printStackTrace();

}

}//-----------------------------------------------------------------------------

public class Sub extendsMain {

@Overridepublic voidserviceMethod() {try{

System.out.println("int sub 下一步 sleep begin threadName="

+ Thread.currentThread().getName() + " time="

+System.currentTimeMillis());

Thread.sleep(5000);

System.out.println("int sub 下一步 sleep end threadName="

+ Thread.currentThread().getName() + " time="

+System.currentTimeMillis());super.serviceMethod();

}catch(InterruptedException e) {

e.printStackTrace();

}

}//-----------------------------------------------------------------------------

public class MyThreadA extendsThread {privateSub sub;publicMyThreadA(Sub sub) {super();this.sub =sub;

}

@Overridepublic voidrun() {

sub.serviceMethod();

}public class MyThreadB extendsThread {privateSub sub;publicMyThreadB(Sub sub) {super();this.sub =sub;

}

@Overridepublic voidrun() {

sub.serviceMethod();

}

}//-----------------------------------------------------------------------------

public classTest {public static voidmain(String[] args) {

Sub subRef= newSub();

MyThreadA a= newMyThreadA(subRef);

a.setName("A");

a.start();

MyThreadB b= newMyThreadB(subRef);

b.setName("B");

b.start();

}

}

synchronized同步语句块

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

public classTask {privateString getData1;privateString getData2;public synchronized voiddoLongTimeTask(){try{

System.out.println("begin task");

Thread.sleep(3000);

getData1="长时间处理任务后从远程返回的值1 threadName="

+Thread.currentThread().getName();

getData2="长时间处理任务后从远程返回的值2 threadName="

+Thread.currentThread().getName();

System.out.println(getData1);

System.out.println(getData2);

System.out.println("end task");

}catch(InterruptedException e){

e.printStackTrace();

}

}

}public classCommonUtils {public static longbeginTime1;public static longendTime1;public static longbeginTime2;public static longendTime2;

}public class ThreadA extendsThread{privateTask task;publicThreadA(Task task){super();this.task=task;

}

@Overridepublic voidrun() {super.run();

CommonUtils.beginTime1=System.currentTimeMillis();

task.doLongTimeTask();

CommonUtils.endTime1=System.currentTimeMillis();

}

}public class ThreadB extendsThread{privateTask task;publicThreadB(Task task){super();this.task=task;

}

@Overridepublic voidrun() {super.run();

CommonUtils.beginTime2=System.currentTimeMillis();

task.doLongTimeTask();

CommonUtils.endTime2=System.currentTimeMillis();

}

}public classRun {public static voidmain(String[] args){

Task task=newTask();

ThreadA thread1=newThreadA(task);

thread1.start();

ThreadB thread2=newThreadB(task);

thread1.start();try{

Thread.sleep(10000);

}catch(InterruptedException e) {

e.printStackTrace();

}long beginTime=CommonUtils.beginTime1;if(CommonUtils.beginTime2

beginTime=CommonUtils.beginTime2;

}long endTime=CommonUtils.endTime1;if (CommonUtils.endTime2>CommonUtils.endTime1){

endTime=CommonUtils.endTime2;

}

System.out.println("耗时:"+(endTime-beginTime)/1000);

}

}

程序运行大约6秒后结束。其中synchronized修饰的方法dolongtimetask同步执行耗时很长。

结论写在前面:不在synchronized块中就是异步执行,在synchronized块中就是同步执行

使用同步代码块解决同步方法的弊端:

1 public classTask {2 privateString getData1;3 privateString getData2;4

5 public synchronized voiddoLongTimeTask(){6 try{7 System.out.println("begin task");8 Thread.sleep(3000);9 getData1="长时间处理任务后从远程返回的值1 threadName="

10 +Thread.currentThread().getName();11 getData2="长时间处理任务后从远程返回的值2 threadName="

12 +Thread.currentThread().getName();13 synchronized (this){14 System.out.println(getData1);15 System.out.println(getData2);16 }17 System.out.println("end task");18 }catch(InterruptedException e){19 e.printStackTrace();20 }21 }22 }

第13-16行代码被修改了,他们被放入了同步代码块中,显然不在同步代码块中的内容被异步执行,程序运行结束后,耗时为3秒。

在使用同步代码块的时候需要注意,当一个线程访问object的一个synchrnized同步代码块时,其他线程对同一个object中所有其他synchronized同步代码块的访问将被阻塞,这说明synchronized使用的对象监视器是同一个。

问题来了,什么是对象监视器?

在JVM的规范中,有这么一些话:

“在JVM中,每个对象和类在逻辑上都是和一个监视器相关联的”

“为了实现监视器的排他性监视能力,JVM为每一个对象和类都关联一个锁”

“锁住了一个对象,就是获得对象相关联的监视器”

从这些话,看出监视器和对象锁好像是一回事,那为何要定义两个东西,若不一样,他们的关系如何?监视器好比一做建筑,它有一个很特别的房间,房间里有一些数据,而且在同一时间只能被一个线程占据,进入这个建筑叫做"进入监视器",进入建筑中的那个特别的房间叫做"获得监视器",占据房间叫做"持有监视器",离开房间叫做"释放监视器",离开建筑叫做"退出监视器".  而一个锁就像一种任何时候只允许一个线程拥有的特权.   一个线程可以允许多次对同一对象上锁.对于每一个对象来说,java虚拟机维护一个计数器,记录对象被加了多少次锁,没被锁的对象的计数器是0,线程每加锁一次,计数器就加1,每释放一次,计数器就减1.当计数器跳到0的时候,锁就被完全释放了.

java虚拟机中的一个线程在它到达监视区域开始处的时候请求一个锁.JAVA程序中每一个监视区域都和一个对象引用相关联.

监视器:monitor

锁:lock(JVM里只有一种独占方式的lock)

进入监视器:entermonitor

离开/释放监视器:leavemonitor

(entermonitor和leavemonitor是JVM的指令)

拥有者:owner

在JVM里,monitor就是实现lock的方式。

entermonitor就是获得某个对象的lock(owner是当前线程)

leavemonitor就是释放某个对象的lock

------------------------->这些内容都是JVM的内容,下一部博文准备写JVM

同步代码块锁非this对象

这里引出新的问题this关键字

(1)this调用本类中的属性,也就是类中的成员变量;

(2)this调用本类中的其他方法;

(3)this调用本类中的其他构造方法,调用时要放在构造方法的首行。

this是一个引用,它指向自身的这个对象。结论写在前面:一.在多个线程持有“对象监视器”为同一个对象的前提下,同一时间只有一个线程可以执行synchronized(非this对象X)同步代码块中的代码

二.当持有“对象监视器”为同一个对象的前提下,同一时间只有一个线程可以执行synchronized(非this对象X)同步代码块中的代码

public classService {privateString usernameParam;privateString passwordParam;private String anString = newString();public voidsetUsernamePassword(String username,String password){try{synchronized(anString){

System.out.println("线程名称是:"+Thread.currentThread().getName()+"在" + System.currentTimeMillis()+"进入同步块");

usernameParam=username;

Thread.sleep(3000);

passwordParam=password;

System.out.println("线程名称是:"+Thread.currentThread().getName()+"在" + System.currentTimeMillis()+"离开同步块");

}

}catch(InterruptedException e) {

e.printStackTrace();

}

}

}public class ThreadA extendsThread{privateService service;publicThreadA(Service service){this.service =service;

}

@Overridepublic voidrun(){

service.setUsernamePassword("a","apsssss");

}

}public class ThreadB extendsThread{privateService service;publicThreadB(Service service){this.service =service;

}

@Overridepublic voidrun(){

service.setUsernamePassword("BBB","ISSSSBBB");

}

}public classRun {public static voidmain(String[] args) {

Service service= newService();

ThreadA a= newThreadA(service);

a.setName("A线程");

a.start();

ThreadB b= newThreadB(service);

b.setName("B线程");

b.start();

}

}

上面的代码运行结果为:

线程名称是:A线程在1574247406143进入同步块

线程名称是:A线程在1574247409171离开同步块

线程名称是:B线程在1574247409172进入同步块

线程名称是:B线程在1574247412174离开同步块

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

public classService {privateString usernameParam;privateString passwordParam;public voidsetUsernamePassword(String username,String password){try{

String anString= newString();synchronized(anString){

System.out.println("线程名称是:"+Thread.currentThread().getName()+"在" + System.currentTimeMillis()+"进入同步块");

usernameParam=username;

Thread.sleep(3000);

passwordParam=password;

System.out.println("线程名称是:"+Thread.currentThread().getName()+"在" + System.currentTimeMillis()+"离开同步块");

}

}catch(InterruptedException e) {

e.printStackTrace();

}

}

}

使用synchronized(非this对象X)同步代码块格式进行同步操作时,对象监视器必须是同一个对象。如果不是同一个对象监视器,运行的结果就是异步调用,就会交叉运行。因为上面代码中声明 anString 的位置发生了变化,可以实现同步的是在对象属性声明的部位创建anString,导致异步结果的事下面这个在方法内声明变量的操作。

三个结论!

synchronized(非this对象X)格式的写法是将x对象本身作为对象监视器,这样就可以得到下面3个结论

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

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

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

但需要注意的是,如果其他线程调用不加synchronized关键字的方法时,还是异步调用。

java丐帮_java多线程学习笔记(五)相关推荐

  1. java丐帮_java多线程学习笔记(三)

    java多线程下的对象及变量的并发访问 上一节讲到,并发访问的时候,因为是多线程,变量如果不加锁的话,会出现"脏读"的现象,这个时候需要"临界区"的出现去解决多 ...

  2. java丐帮_Java多线程学习笔记(一)

    一.什么是多线程 首先是多线程的概念: 多线程是异步的,和单任务不同,并不一定按照代码的执行顺序(上图左)来运行,而是交错占用CPU运行(上图右): 二.如何使用多线程 JAVA多线程有两种实现方式: ...

  3. java丐帮_java多线程学习笔记(四)

    上一节讲到Synchronized关键字,synchronized上锁的区域:对象锁=方法锁/类锁 本节补充介绍一下synchronized锁重入: 关键字synchronized拥有锁重入的功能,也 ...

  4. java丐帮_java多线程学习笔记(二)

    上一节讲到多线程的创建,两种创建方式一种继承Thread类,一种实现Runnable接口: 常用的多线程函数: currentThread()方法        返回代码段正在被哪个线程调用的信息 i ...

  5. java丐帮_java多线程学习笔记(八)

    本节开始线程间通信: 使用wait/notify实现线程间通信 生产者/消费者模式的实现 方法join的使用 ThreadLocal类的使用 可以通过使用 sleep() 结合 while(true) ...

  6. java丐帮_java多线程学习笔记(六)

    本节开始synchronized关键字的最后一部分内容: 静态同步方法synchronized方法与synchronized(class)代码块 关键字synchronized还可以用在static静 ...

  7. Java之多线程学习笔记五 —— 多线程模拟龟兔赛跑

    Java之多线程学习笔记五 -- 多线程模拟龟兔赛跑 参考教程B站狂神https://www.bilibili.com/video/BV1V4411p7EF package pers.ylw.less ...

  8. java 编程思想 多线程学习笔记

    java 编程思想 多线程学习笔记 一.如何创建多线程? 1.继承 java.lang.Thread 类 2.实现 java.lang.Runnable 接口 3.Callable接口 总之,在任何线 ...

  9. java线程集合点_Java多线程学习笔记(三) 甚欢篇

    使人有乍交之欢,不若使其无久处之厌 <小窗幽记>很多时候,我们需要的都不是再多一个线程,我们需要的线程是许多个,我们需要让他们配合.同时我们还有一个愿望就是复用线程,就是将线程当做一个工人 ...

最新文章

  1. OpenStack之虚拟机热迁移
  2. web安全之windows系统基础
  3. WPF入门(一)——绑定Binding
  4. Java zip 压缩 文件夹删除,移动,重命名,复制
  5. 没有数学天赋是一种什么体验?
  6. leetcode1302. 层数最深叶子节点的和(深度优先搜索)
  7. Android入门(11)| 全局广播与本地广播
  8. sql2005-数据库备份方案
  9. Android脚本打包
  10. 今天写了一个含配置文件的 文件分割 及 合并 的java程序。
  11. 电脑硬件知识学习_31岁,还在熬夜学习到2点的背后,是一个丈夫和父亲的责任与担当...
  12. 或为红米8A 卢伟冰确认将推出5000mAh新机
  13. Oracle中给表添加主键 外键,给表中添加主键、外键
  14. [ SHELL编程 ] 远程服务器传输文件
  15. 微信小程序开发——小程序分享转发
  16. Redisson实现分布式锁
  17. DAC,模数转换,使用Python,Matlab生产正弦码表(整型和浮点型)
  18. 民间借贷、网贷vs信用卡
  19. linux安装git lfs
  20. 互联网进化论在中国科技论文在线正式发表

热门文章

  1. win7打开网络无计算机,Win7电脑系统IPV6无网络访问权限解决方法
  2. CometOJ #10 沉鱼落雁 | 思维
  3. Kafka+zookeeper集群搭建
  4. 值得你收藏的几个实用识别图片文字软件都在这
  5. java之父詹姆斯高斯林的传奇人生
  6. 詹姆斯高斯林_詹姆斯·高斯林(James Gosling):Oracle的表现“令人惊讶的是” 用Java
  7. Qtablewidget设置某一列不可编辑
  8. 学计算机惠普和联想笔记本哪个好,笔记本做得好,未必只有惠普和联想
  9. “燕云十六将”之Lorna(14)
  10. 从零开始搭建个人大数据集群——环境准备篇