1.Synchronized使用范围:

  • 同步普通方法:锁的是当前对象

    

 1 //包含synchronized修饰的同步方法的类addCountClass
 2 public class addCountClass {
 3
 4     private  int count = 0;
 5
 6     synchronized public void addCount(String user)
 7     {
 8         try
 9         {
10             if(user.equals("a"))
11             {
12                 count = 100;
13                 System.out.println("a set count = 100,over");
14                 Thread.sleep(3000);
15             }else
16             {
17                 count = 200;
18                 System.out.println("b set count = 200,over");
19             }
20             System.out.println(user+" count = "+count);
21
22         } catch (Exception e) {
23             e.printStackTrace();
24         }
25
26     }
27 }

//线程类A
public class ThreadA extends Thread {private addCountClass addcount1;public ThreadA(addCountClass addcount) {super();this.addcount1 = addcount;}public void run() {super.run();addcount1.addCount("a");}
}

//线程类B
public class ThreadB extends Thread {private addCountClass addcount2;public ThreadB(addCountClass addcount) {super();this.addcount2 = addcount;}public void run() {super.run();addcount2.addCount("b");}}

//测试类
public class MainClass {public static void main(String[] args) {addCountClass addCount1 = new addCountClass();addCountClass addCount2 = new addCountClass();//线程th1启动后,调用addCount方法时,是用对象addCount1来调用的Thread th1 = new ThreadA(addCount1);//线程th2启动后,调用addCount方法时,是用对象addCount2来调用的Thread th2 = new ThreadB(addCount2);th1.start();th2.start();}}

//输出结果
a set count = 100,over
b set count = 200,over
b count = 200
a count = 100/*分析上述结果可知,因为类中Synchronized关键字修饰的是普通方法,*因此锁定的是当前的对象,所以两次调用时分别锁定了addCount1和*addCount2,所以两个线程都能够正常访问,互不影响
*/

  • 同步静态方法:锁的是当前class(类)对象

 1 //将上一个例子中的addCount方法修改为类中的static方法
 2 public class addCountClass {
 3
 4     private static  int count = 0;
 5
 6     synchronized public static void addCount(String user)
 7     {
 8         try
 9         {
10             if(user.equals("a"))
11             {
12                 count = 100;
13                 System.out.println("a set count = 100,over");
14                 Thread.sleep(3000);
15             }else
16             {
17                 count = 200;
18                 System.out.println("b set count = 200,over");
19             }
20             System.out.println(user+" count = "+count);
21
22         } catch (Exception e) {
23             e.printStackTrace();
24         }
25     }
26 }

//运行结果
a set count = 100,over
a count = 100
b set count = 200,over
b count = 200/**此时可以看到,执行结果只可能是一个线程完全执行完addCount方法后*另一个线程才能够进入该方法,这是因为此时Synchronized修饰的是类*中的静态方法,因此锁定的当前的class对象,即当前类。因此无论是*addCount1还是addCount2来调用addCount方法,都会锁定当前类对象
*/

  • 同步代码块:锁的是()中的对象,synchronized(this)代码块也是锁定当前对象

  当某个需要同步的方法中并不是所有的部分都需要同步时,可将需要同步的代码块用synchronized来修饰,可以提高程序并发效果。

 1 //案例1,整个方法都加上了Syncchronized关键字
 2 public class Task {
 3
 4     private int a = 0;
 5     synchronized public void longTimeTask()
 6     {
 7         //模拟一个长时间的无需同步的任务
 8         System.out.println("no need Synchronized task start");
 9         try {
10             Thread.sleep(3000);
11         } catch (InterruptedException e) {
12             e.printStackTrace();
13         }
14         System.out.println("no need Synchronized task end");
15
16         //需要同步的任务
17         System.out.println("Synchronized task start");
18         try {
19             Thread.sleep(1000);
20         } catch (InterruptedException e) {
21             e.printStackTrace();
22         }
23         System.out.println("Synchronized task end");
24     }
25 }

View Code

 1 //Thread类A
 2 public class ThreadA extends Thread {
 3     private Task task;
 4     public ThreadA(Task task)
 5     {
 6         super();
 7         this.task = task;
 8     }
 9
10     public void run()
11     {
12         super.run();
13         task.longTimeTask();
14     }
15 }

View Code

 1 public class ThreadB extends Thread {
 2     private Task task;
 3     public ThreadB(Task task)
 4     {
 5         super();
 6         this.task = task;
 7     }
 8
 9     public void run()
10     {
11         super.run();
12         task.longTimeTask();
13     }
14 }

View Code

 1 //测试类
 2 public class MainClass2 {
 3
 4     public static void main(String[] args) throws Exception {
 5         long startTime = System.currentTimeMillis();
 6
 7         Task task = new Task();
 8         Thread th1 = new ThreadA(task);
 9         Thread th2 = new ThreadB(task);
10
11         th1.start();
12         th2.start();
13
14         th2.join();
15
16         long totalTime = System.currentTimeMillis()-startTime;
17         System.out.println("程序总计用时:"+ totalTime);
18
19     }
20
21 }

//输出结果
no need Synchronized task start
no need Synchronized task end
Synchronized task start
Synchronized task end
no need Synchronized task start
no need Synchronized task end
Synchronized task start
Synchronized task end
程序总计用时:8006毫秒

分析上述结果可知,两个线程分别去调用加锁方法,第二个需要等到第一个执行完加锁方法中的全部步骤后才可进入执行,即使其中有一部分是无需线程同步的。

修改上述加锁部分,将Synchronized关键字只加到需要同步的代码块上:

 1 public class Task {
 2
 3     private int a = 0;
 4      public void longTimeTask()
 5     {
 6         //模拟一个长时间的无需同步的任务
 7         System.out.println("no need Synchronized task start");
 8         try {
 9             Thread.sleep(3000);
10         } catch (InterruptedException e) {
11             e.printStackTrace();
12         }
13         System.out.println("no need Synchronized task end");
14
15         //只在需要同步的任务前加上synchronized
16         synchronized(this)
17         {
18             System.out.println("Synchronized task start");
19             try {
20                 Thread.sleep(1000);
21             } catch (InterruptedException e) {
22                 e.printStackTrace();
23             }
24             System.out.println("Synchronized task end");
25         }
26     }
27 }

最终程序执行结果为:

//程序运行结果
no need Synchronized task start
no need Synchronized task start
no need Synchronized task end
no need Synchronized task end
Synchronized task start
Synchronized task end
Synchronized task start
Synchronized task end
程序总计用时:5010毫秒

分析上述结果可知,此时线程th1和th2访问longTimeTask方法,但是其中一部分为无需线程同步的,两个线程可以并发执行,而加上了Sychronized方法的代码块。则会在第一个线程进入时加上

task对象锁,第二个线程进入该代码块时不能获取到该锁,所以该代码块无法并行,最终使用代码块加锁的方式,在不影响程序正常执行的情况下,提高了程序并发。

  

  

2.实现原理:JVM 是通过进入、退出对象监视器( Monitor )来实现对方法、同步块的同步的。

具体实现是在编译之后在同步方法调用前加入一个 monitor.enter 指令,在退出方法和异常处插入 monitor.exit 的指令。

其本质就是对一个对象监视器( Monitor )进行获取,而这个获取过程具有排他性从而达到了同一时刻只能一个线程访问的目的。

而对于没有获取到锁的线程将会阻塞到方法入口处,直到获取锁的线程 monitor.exit 之后才能尝试继续获取锁。

转载于:https://www.cnblogs.com/LearnAndGet/p/9679076.html

java多线程系列1:Sychronized关键字相关推荐

  1. Java多线程系列---“JUC锁”01之 框架

    本章,我们介绍锁的架构:后面的章节将会对它们逐个进行分析介绍.目录如下: 01. Java多线程系列--"JUC锁"01之 框架 02. Java多线程系列--"JUC锁 ...

  2. Java多线程系列(四):4种常用Java线程锁的特点,性能比较、使用场景

    多线程的缘由 在出现了进程之后,操作系统的性能得到了大大的提升.虽然进程的出现解决了操作系统的并发问题,但是人们仍然不满足,人们逐渐对实时性有了要求. 使用多线程的理由之一是和进程相比,它是一种非常花 ...

  3. Java多线程系列(七):并发容器的原理,7大并发容器详解、及使用场景

    之前谈过高并发编程系列: 高并发编程系列:4种常用Java线程锁的特点,性能比较.使用场景 高并发编程系列:CountDownLatch.Semaphore等4大并发工具类详解 高并发编程系列:4大J ...

  4. java多线程系列(一)

    java多线程技能 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我 ...

  5. Java多线程系列之“JUC集合“详解

    Java集合包 在"Java 集合系列01之 总体框架"中,介绍java集合的架构.主体内容包括Collection集合和Map类:而Collection集合又可以划分为List( ...

  6. Java多线程系列--AQS的原理

    原文网址:Java多线程系列--AQS的原理_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Java中的AQS的原理. Java的AQS是JDK自带的锁机制,是JUC(java.util.concu ...

  7. java多线程系列(四)---ReentrantLock的使用

    Lock的使用 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理 ...

  8. Java多线程系列--“JUC原子类”01之 框架

    2019独角兽企业重金招聘Python工程师标准>>> Java多线程系列--"JUC原子类"01之 框架 根据修改的数据类型,可以将JUC包中的原子操作类可以分 ...

  9. Java多线程系列--“JUC原子类”03之 AtomicLongArray原子类

    概要 AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray这3个数组类型的原子类的原理和用法相似.本章以AtomicLongArray对数 ...

  10. Java多线程系列--“JUC线程池”06之 Callable和Future

    转载自  Java多线程系列--"JUC线程池"06之 Callable和Future Callable 和 Future 简介 Callable 和 Future 是比较有趣的一 ...

最新文章

  1. String常用操作,StringBuffer。
  2. 网络营销专员浅析在网络营销中网站关键词对网站流量获取有何影响?
  3. CentOS安装libpcap
  4. Java基础知识总结(一)
  5. vb.net datagridview数据批量导入sql_【自学C#】|| 笔记 44 ComboBox:组合框控件数据绑定...
  6. python语言format用法_python格式化输出之format用法
  7. 苹果启动“突围”计划 建立自营金融服务
  8. 基于DTW和HMM算法的语音识别系统对比研究-毕业小结
  9. 机器人matlab仿真步骤,MATLAB机器人仿真程序.doc
  10. Java常用开发工具有哪些?
  11. linux电子表格工具,Linux系统办公一条龙之电子表格Calc
  12. homeassistant搭建_安卓环境home assistant搭建
  13. MNE预处理脑电数据
  14. CentOS5u11 Oracle 10g 生产RMAN备份可用性恢复测试
  15. 软件工程应届生面试题
  16. FinalShell连接不上LinuxCentOS-7的解决方案
  17. Cubase中MIDI设备的如何添加面板
  18. 分享通达信选股公式源码
  19. Codeforces #199前三题
  20. 设计一个采购、销售和客户管理应用数据库

热门文章

  1. 【vue】webpack打包vue项目并且运行在Tomcat里面
  2. Oracle EXPDP/IMPDP示例
  3. 指定一个开始日期和结束日期,算出中间的日期
  4. iOS中 支付宝钱包详解/第三方支付 韩俊强的博客
  5. Linux服务器信息检测Shell脚本
  6. Oracle PL/SQL编程学习笔记:游标
  7. 准爸爸日记——20120502海淀妇幼建档续
  8. Android改变移动网络ip地址,Android之获取移动网络ip
  9. Metasploit运行环境内存不要低于2GB
  10. iOS Sprite Kit教程之真机测试以及场景的添加与展示