1.Synchronized使用范围:

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

    

 //包含synchronized修饰的同步方法的类addCountClass
public class addCountClass { private int count = 0; synchronized public void addCount(String user)
{
try
{
if(user.equals("a"))
{
count = 100;
System.out.println("a set count = 100,over");
Thread.sleep(3000);
}else
{
count = 200;
System.out.println("b set count = 200,over");
}
System.out.println(user+" count = "+count); } catch (Exception e) {
e.printStackTrace();
} }
}
//线程类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(类)对象

 //将上一个例子中的addCount方法修改为类中的static方法
public class addCountClass { private static int count = 0; synchronized public static void addCount(String user)
{
try
{
if(user.equals("a"))
{
count = 100;
System.out.println("a set count = 100,over");
Thread.sleep(3000);
}else
{
count = 200;
System.out.println("b set count = 200,over");
}
System.out.println(user+" count = "+count); } catch (Exception e) {
e.printStackTrace();
}
}
}
//运行结果
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,整个方法都加上了Syncchronized关键字
public class Task { private int a = 0;
synchronized public void longTimeTask()
{
//模拟一个长时间的无需同步的任务
System.out.println("no need Synchronized task start");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("no need Synchronized task end"); //需要同步的任务
System.out.println("Synchronized task start");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Synchronized task end");
}
}
 //Thread类A
public class ThreadA extends Thread {
private Task task;
public ThreadA(Task task)
{
super();
this.task = task;
} public void run()
{
super.run();
task.longTimeTask();
}
}
 public class ThreadB extends Thread {
private Task task;
public ThreadB(Task task)
{
super();
this.task = task;
} public void run()
{
super.run();
task.longTimeTask();
}
}
 //测试类
public class MainClass2 { public static void main(String[] args) throws Exception {
long startTime = System.currentTimeMillis(); Task task = new Task();
Thread th1 = new ThreadA(task);
Thread th2 = new ThreadB(task); th1.start();
th2.start(); th2.join(); long totalTime = System.currentTimeMillis()-startTime;
System.out.println("程序总计用时:"+ totalTime); } }
//输出结果
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关键字只加到需要同步的代码块上:

 public class Task {

     private int a = 0;
public void longTimeTask()
{
//模拟一个长时间的无需同步的任务
System.out.println("no need Synchronized task start");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("no need Synchronized task end"); //只在需要同步的任务前加上synchronized
synchronized(this)
{
System.out.println("Synchronized task start");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Synchronized task end");
}
}
}

最终程序执行结果为:

//程序运行结果
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 之后才能尝试继续获取锁。

java多线程系列1:Sychronized关键字的更多相关文章

  1. [java基础]一文理解java多线程必备的sychronized关键字,从此不再混淆!

    java并发编程中最长用到的关键字就是synchronized了,这里讲解一下这个关键字的用法和容易混淆的地方. synchronized关键字涉及到锁的概念, 在java中,synchronized ...

  2. Java多线程系列--“基础篇”04之 synchronized关键字

    概要 本章,会对synchronized关键字进行介绍.涉及到的内容包括:1. synchronized原理2. synchronized基本规则3. synchronized方法 和 synchro ...

  3. Java多线程系列——原子类的实现(CAS算法)

    1.什么是CAS? CAS:Compare and Swap,即比较再交换. jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronou ...

  4. Java多线程系列——从菜鸟到入门

    持续更新系列. 参考自Java多线程系列目录(共43篇).<Java并发编程实战>.<实战Java高并发程序设计>.<Java并发编程的艺术>. 基础 Java多线 ...

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

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

  6. Java多线程系列目录(共43篇)

    最近,在研究Java多线程的内容目录,将其内容逐步整理并发布. (一) 基础篇 01. Java多线程系列--“基础篇”01之 基本概念 02. Java多线程系列--“基础篇”02之 常用的实现多线 ...

  7. Java多线程系列--“JUC锁”06之 Condition条件

    概要 前面对JUC包中的锁的原理进行了介绍,本章会JUC中对与锁经常配合使用的Condition进行介绍,内容包括:Condition介绍Condition函数列表Condition示例转载请注明出处 ...

  8. Java多线程系列--“基础篇”11之 生产消费者问题

    概要 本章,会对“生产/消费者问题”进行讨论.涉及到的内容包括:1. 生产/消费者模型2. 生产/消费者实现 转载请注明出处:http://www.cnblogs.com/skywang12345/p ...

  9. Java多线程系列--“基础篇”05之 线程等待与唤醒

    概要 本章,会对线程等待/唤醒方法进行介绍.涉及到的内容包括:1. wait(), notify(), notifyAll()等方法介绍2. wait()和notify()3. wait(long t ...

  10. Java多线程系列--“基础篇”06之 线程让步

    概要 本章,会对Thread中的线程让步方法yield()进行介绍.涉及到的内容包括:1. yield()介绍2. yield()示例3. yield() 与 wait()的比较 转载请注明出处:ht ...

随机推荐

  1. 北京化妆时尚气息自适应CSS例子

    三里屯太古广场——北京化妆时尚气息的先锋阵地! “乐色起义”创意化妆设计大赛——国内最具创意的公益设计大赛! CNature——国内最具个性的时尚环保公益组织! 一个多么奇妙的组合!就在2010年的这 ...

  2. Linux下如何查看CPU型号、个数、核数、逻辑CPU数、位数、发行版本、内核信息、内存、服务器生产厂家

    [原文链接]:http://blog.csdn.net/mdx20072419/article/details/7767809 http://blog.chinaunix.net/uid-224252 ...

  3. osworkflow 入门基础

    OSWorkFlow入门指南目的 这篇指导资料的目的是介绍OSWorkflow的所有概念,指导你如何使用它,并且保证你逐步理解OSWorkflow的关键内容. 本指导资料假定你已经部署OSWorkfl ...

  4. PAT Basic 1007 素数对猜想 (20 分)

    让我们定义d​n​​为:d​n​​=p​n+1​​−p​n​​,其中p​i​​是第i个素数.显然有d​1​​=1,且对于n>1有d​n​​是偶数.“素数对猜想”认为“存在无穷多对相邻且差为2的素 ...

  5. 多线程-生产者消费者(synchronized同步)

    正解博客:https://blog.csdn.net/u011863767/article/details/59731447 永远在循环(loop)里调用 wait 和 notify,不是在 If 语 ...

  6. python 继承:重写、拓展(六)

    1.继承:父类有的子类也有 2.多继承:若继承多个父类有相同的函数,则继承前面的函数,传递参数的个数也与继承的函数位置有关 3.超继承:针对继承一个父类使用,不仅有父类的特写同时也有自己的新特性  s ...

  7. ES修改最大分页数

    curl -XPUT http://localhost:9200/my_index/_settings?preserve_existing=true -H 'Content-Type: applica ...

  8. 【leetcode】1262. Greatest Sum Divisible by Three

    题目如下: Given an array nums of integers, we need to find the maximum possible sum of elements of the a ...

  9. VM删除快照失败,磁盘空间不足,只是删除了快照名字(全网唯一解决办法)

    原创: 删除之前的快照,发现只是把名字删除了, 看着这么多文件也不知道怎么删,一顿百度google也是没找到答案 于是就自己琢磨 因为删除快照的时候,是先把快照删除,然后删除无效的文件 所以先让这个盘 ...

  10. springboot整合admin管理平台

    server 端 <parent> <groupId>org.springframework.boot</groupId> <artifactId>sp ...