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. 教你用python爬取网站美女图(附代码及教程)

    我前几篇文章都是说一些python爬虫库的用法,还没有说怎样利用好这些知识玩一些好玩的东西.那我今天带大家玩好玩又刺激的,嘻嘻!对了,requests库和正则表达式很重要的,一定要学会!一定要学会!! ...

  2. Nginx之常用操作

    1) 将XXX.com 重定向到 www.XXX.com server { client_max_body_size 20m; listen ; server_name www.xxx.com xxx ...

  3. linux下ifconfig只剩下lo的解决方法

    运行以下命令,删除旧的网络配置,重新让networkmanager自动配置即可 sudo service network-manager stop sudo rm /var/lib/NetworkMa ...

  4. tomcat性能优化,内存优化和并发线程连接优化

    今天被一同事问到tomcat和内存优化的问题,而网上的资料基本都是来回copy,所以抽时间随便写点.文章中设置的参数都是一个随便写的,具体的还要根据自己的情况来定. 1.内存优化: 说到tomcat不 ...

  5. 11、Nginx反向代理服务

    1Nginx代理服务基本概述 1.代理一词并不陌生, 该服务我们常常用到如(代理理财.代理租房.代理收货等等),如下图所示 2.在没有代理模式的情况下,客户端和Nginx服务端,都是客户端直接请求服务 ...

  6. 第二篇.2、python基础之字符编码

    一 了解字符编码的知识储备 一 计算机基础知识 二 文本编辑器存取文件的原理(nodepad++,pycharm,word) #1.打开编辑器就打开了启动了一个进程,是在内存中的,所以,用编辑器编写的 ...

  7. Java语言基础(5)

    1 if-else语句(二) 案例:Demo1~Demo4 import java.util.Scanner; public class Demo1 { //在main方法中,从控制台输入任意的一个整 ...

  8. parfile解决exp时tables过多问题

    parfile 一般用于表数据过大.使用导出.导入命令参数过多等场景: 在对oracle数据库使用exp命令导出数据时,如果tables=后面跟的表比较多,就是导致命令行放不下,从而不能导出.百度一把 ...

  9. constant read 和 current read

    来自网络,并且在本机实验完成: onsistent read :我的理解,就是通过scn来读取.  读取的过程中要保证 scn是一致的.举个例子,一个SELECT 语句在SCN=100的时刻开始读取一 ...

  10. k8sDeployment控制器

    简写为deploy,是k8s控制器的另一种实现,它构建于ReplicaSet之上,可为pod和rs资源提供声明式更新. deploy控制器资源的大部分功能均可通过调用rs来实现,同时,还增添了部分特性 ...