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. Django框架——基础之模板系统(template文件夹)

    ---恢复内容开始--- 1. 常用语法 需要记住两组特殊符号:{{  }}  和 {%  %}. 在运用到变量的时候使用{{  }},如果是跟逻辑相关的话就使用{%  %}. 在Django模板(t ...

  2. vue组件之子组件和父组件

    在看官网和学习的过程中,有些不明确子组件和父组件的定义,为了方便后期学习和理解去网站上搜索了一下相关的解释 1.使用的地方是父组件,定义的地方是子组件,虽然他们是同一个组件 2.Vue.compone ...

  3. 查询SAP数据库表的大小

    事物代码DB02 Perfomrmance->Additional Functions->SQL Command Editor->写数据表->执行 select bytes/1 ...

  4. 一头扎进 JAVA

    硅不可 吉米 JAVA 基础 -- 基础不牢,地动山摇 子类应该比 父类更为 开放 (public protected default private) 子类方法不能比父类抛出更高异常( 可以为父类方 ...

  5. 超详细思路讲解SQL语句的查询实现,及数据的创建。

    最近一直在看数据库方面的问题,总结了一下SQL语句,这是部分详细的SQL问题,思路讲解: 第一步:创建数据库表,及插入数据信息 --Student(S#,Sname,Sage,Ssex) 学生表 CR ...

  6. MySQL单机上多实例安装

    首先安装mysql,不要启动MySQL,先配置vim /etc/my.cnf.[mysqld_multi]mysqld = /usr/bin/mysqld_safemysqladmin = /usr/ ...

  7. c++ easyX的学习

    画象棋盘来浅显学习了解easyx 了解象棋盘的构成: 如图就为一个基本的象棋棋盘我们下面就用esayx来画出这个棋盘,我的感觉这个棋盘大概分为两个部分:第一部分就是棋盘的大致布局,第二个就是棋盘的细节 ...

  8. GeoJson格式与转换(shapefile)Geotools

    转自:https://blog.csdn.net/cobramonkey/article/details/71124888 作为大数据分析的重要工具,Hadoop在这一领域发挥着不可或缺的作用.有些人 ...

  9. 修改Anaconda启动时默认路径

    1.找到Anoconda启动快捷方式,入下图: 2.右击点击属性,进入下图: 3.将第三行的 目标(T):  ......D:\Anoconda\Scripts\jupyter-notebook-sc ...

  10. Linux环境测试机器端口连通性

    生产中,有很大一部分的问题都是由于不同机器间网络不同导致的,那么如何判断两台机器之间的连通性?本文介绍几种常见的方式: telnet方法wget方法ssh方法curl方法1. telnet方法格式:t ...