在java编程中,经常需要用到同步,而同步的实现使用最多的就是synchronized关键字了。

synchronized关键字涉及到“锁”的概念,首先先了解一下相关锁的知识。

java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁。线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。

java内置锁是一个互斥锁,这就是意味着最多只有一个线程能够获得该锁,当线程A尝试去获得线程B持有的内置锁时,线程A必须等待或者阻塞,直到线程B释放这个锁,如果B线程不释放这个锁,那么A线程将永远等待下去。

java中的锁按级别可分为:对象锁或方法锁,类锁这两种。

java的对象锁(或方法锁)和类锁在锁的概念上与内置锁基本一致,但对象锁和类锁之间是有很大区别的。

区别:1、对象锁用于对象实例方法,类锁是用于类的静态方法或者一个类的class对象上。

     2、类的对象可以有多个,所以不同的对象实例可以有多个对象锁,且互不干扰。每个类只有一个class对象,所以每个类只有一个类锁。

synchronized的用法:synchronized修改方法或者synchronized修饰代码块。

下面通过具体实例分析两种用法在对象锁和类锁上区别:

对象锁的synchronized修饰方法和代码块:

public class TestSynchronizedForObjectLock {

    public void test1(){
synchronized(this){
int i=5;
while(i-- > 0){
System.out.println(Thread.currentThread().getName() + ":" + i); try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
} public synchronized void test2(){
int i =5;
while(i-- > 0){
System.out.println(Thread.currentThread().getName() + ":" + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} public static void main(String[] args) {
TestSynchronizedForObjectLock t = new TestSynchronizedForObjectLock();
Thread t1 = new Thread(new Runnable(){public void run(){t.test1();}},"test1");
Thread t2 = new Thread(new Runnable(){public void run(){t.test2();}},"test2"); t1.start();
t2.start();
} }

其运行结果:

test1:4
test1:3
test1:2
test1:1
test1:0
test2:4
test2:3
test2:2
test2:1
test2:0

上述的代码,第一个方法时用了同步代码块的方式进行同步,传入的对象实例是this,表明是当前对象;第二个方法是修饰方法的方式进行同步。因为第一个同步代码块传入的this,所以两个同步代码所需要获得的对象锁都是同一个对象锁,下面main方法时分别开启两个线程,分别调用test1和test2方法,那么两个线程都需要获得该对象锁,另一个线程必须等待。上面也给出了运行的结果可以看到:直到test1线程执行完毕,释放掉锁,test2线程才开始执行。

如果我们把test2方法的synchronized关键字去掉,执行结果会如何呢?运行结果:

test1:4
test2:4
test2:3
test1:3
test2:2
test1:2
test2:1
test1:1
test2:0
test1:0

上面是执行结果,我们可以看到,结果输出是交替着进行输出的,这是因为,某个线程得到了对象锁,但是另一个线程还是可以访问没有进行同步的方法或者代码。进行了同步的方法(加锁方法)和没有进行同步的方法(普通方法)是互不影响的,一个线程进入了同步方法,得到了对象锁,其他线程还是可以访问那些没有同步的方法(普通方法)。

所以synchronized只是一个内置锁的加锁机制,当某个方法加上synchronized关键字后,就表明要获得该内置锁才能执行,并不能阻止其他线程访问不需要获得该内置锁的方法。

类锁的synchronized修饰方法和代码块:

public class TestSynchronizedForClassLock {

    public void test3(){

        synchronized(this.getClass()){
int i=5;
while(i-- > 0){
System.out.println(Thread.currentThread().getName() + ":" + i); try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
} public static synchronized void test4(){
int i=5;
while(i-- > 0){
System.out.println(Thread.currentThread().getName() + ":" + i); try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} public static void main(String[] args) {
TestSynchronizedForClassLock c = new TestSynchronizedForClassLock();
Thread t3 = new Thread(new Runnable(){public void run(){c.test3();}});
Thread t4 = new Thread(new Runnable(){public void run(){TestSynchronizedForClassLock.test4();}}); t3.start();
t4.start(); }
}

运行结果:

Thread-0:4
Thread-0:3
Thread-0:2
Thread-0:1
Thread-0:0
Thread-1:4
Thread-1:3
Thread-1:2
Thread-1:1
Thread-1:0

其实,类锁修饰方法和代码块的效果和对象锁是一样的,因为类锁只是一个抽象出来的概念,只是为了区别静态方法的特点,因为静态方法是所有对象实例共用的,所以对应着synchronized修饰的静态方法的锁也是唯一的,所以抽象出来个类锁。其实这里的重点在下面这块代码,synchronized同时修饰静态和非静态方法:

public class TestSynchronizedForClassLock {

    public synchronized void test3(){

            int i=5;
while(i-- > 0){
System.out.println(Thread.currentThread().getName() + ":" + i); try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} } public static synchronized void test4(){
int i=5;
while(i-- > 0){
System.out.println(Thread.currentThread().getName() + ":" + i); try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} public static void main(String[] args) {
TestSynchronizedForClassLock c = new TestSynchronizedForClassLock();
Thread t3 = new Thread(new Runnable(){public void run(){c.test3();}});
Thread t4 = new Thread(new Runnable(){public void run(){TestSynchronizedForClassLock.test4();}}); t3.start();
t4.start(); }
}

运行结果:

Thread-0:4
Thread-1:4
Thread-0:3
Thread-1:3
Thread-0:2
Thread-1:2
Thread-0:1
Thread-1:1
Thread-1:0
Thread-0:0

上面代码synchronized同时修饰静态方法和实例方法,但是运行结果是交替进行的,这证明了类锁和对象锁是两个不一样的锁,控制着不同的区域,它们是互不干扰的。同样,线程获得对象锁的同时,也可以获得该类锁,即同时获得两个锁,这是允许的。

java的同步实现的更多相关文章

  1. java多线程-同步块

    Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java 同步块用来避免竞争.本文介绍以下内容: Java 同步关键字(synchronzied) 实例方法同步 ...

  2. 一篇搞定RSA加密与SHA签名|与Java完全同步

    基础知识 什么是RSA?答:RSA是一种非对称加密算法,常用来对传输数据进行加密,配合上数字摘要算法,也可以进行文字签名. RSA加密中padding?答:padding即填充方式,由于RSA加密算法 ...

  3. Java多线程同步问题的探究

    一.线程的先来后到——问题的提出:为什么要有多线程同步?Java多线程同步的机制是什么? http://www.blogjava.net/zhangwei217245/archive/2010/03/ ...

  4. java 线程同步 原理 sleep和wait区别

    java线程同步的原理java会为每个Object对象分配一个monitor, 当某个对象(实例)的同步方法(synchronized methods)被多个线程调用时,该对象的monitor将负责处 ...

  5. Java线程同步_1

    Java线程同步_1 synchronized 该同步机制的的核心是同步监视器,任何对象都可以作为同步监视器,代码执行结束,或者程序调用了同步监视器的wait方法会导致释放同步监视器 synchron ...

  6. 转:关于JAVA多线程同步

    转:http://lanvis.blog.163.com/blog/static/26982162009798422547/ 因为需要,最近关注了一下JAVA多线程同步问题.JAVA多线程同步主要依赖 ...

  7. java多线程同步

    一篇好文:java多线程机制同步原则 概括起来说,Java 多线程同步机制主要包含如下几点:1:如果一个类包含一个或几个同步方法,那么由此类生成的每一个对象都配备一个队列用来容纳那些等待执行同步的线程 ...

  8. java多线程——同步块synchronized详解

    Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java同步块用来避免竞争.本文介绍以下内容: Java同步关键字(synchronzied) 实例方法同步 静 ...

  9. Java线程同步之一--AQS

    Java线程同步之一--AQS 线程同步是指两个并发执行的线程在同一时间不同时执行某一部分的程序.同步问题在生活中也很常见,就比如在麦当劳点餐,假设只有一个服务员能够提供点餐服务.每个服务员在同一时刻 ...

  10. java 轻量级同步volatile关键字简介与可见性有序性与synchronized区别 多线程中篇(十二)

    概念 JMM规范解决了线程安全的问题,主要三个方面:原子性.可见性.有序性,借助于synchronized关键字体现,可以有效地保障线程安全(前提是你正确运用) 之前说过,这三个特性并不一定需要全部同 ...

随机推荐

  1. (转) Dissecting Reinforcement Learning-Part.2

    Dissecting Reinforcement Learning-Part.2 Jan 15, 2017 • Massimiliano Patacchiola 原文链接:https://mpatac ...

  2. UVA 11019 Matrix Matcher(哈希)

    题意 给定一个 \(n\times m\) 的矩阵,在给定一个 \(x\times y\) 的小矩阵,求小矩阵在大矩阵中出现的次数. \(1 \leq n,m \leq 1000\) \(1\leq ...

  3. 授权oAuth

    使用Client Credentials Grant授权方式给客户端发放access token 只验证客户端(Client),不验证用户(Resource Owner),只要客户端通过验证就发acc ...

  4. Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project ppcloud-common: Compilation failure

    本文为博主原创,未经允许不得转载: [INFO] Finished at: 2018-09-19T20:26:05+08:00[INFO] ------------------------------ ...

  5. 基于OpenNetVM配置环境的发包实践

    参考: openNetVM 基于OpenNetVM配置环境的发包实践 注意:本文并未对OpenNetVM的服务链进行测试,而是在借助OpenNetVM脚本环境的情况下,分别对Pktgen和MoonGe ...

  6. springmvc后台接前端的参数,数组,集合,复杂对象等

    springmvc后台接前端的参数,数组,集合,复杂对象等 参考地址:https://blog.csdn.net/feicongcong/article/details/54705933  常用的几种 ...

  7. 手动添加jar包到maven仓库

    引言: 虽然配置了maven以后可以通过索引的方式自动下载jar包到本地maven仓库,从而使项目中直接使用本地仓库里面的架包, 但是这一招并不是每一次都灵应,也有遇到了失败的时候,当遇到失败的时候, ...

  8. SSL证书申请,如何快速通过SSL文件验证。

    申请SSL证书会让我们进行验证域名,一般方式如下: 1.FTP验证 2.文件验证 3.DNS验证 这三种方式各有各的优缺点,本文解决如何在IIS的环境下通过sslforfree网站的文件验证. 域名: ...

  9. oracle 存储过程给另一个用户的权限问题

    grant execute on (包名)存储过程名称 to 用户名; grant debug on  (包名)存储过程名称 to 用户名 grant select on  存储过程名称 to 用户名 ...

  10. 《剑指offer》第五十一题(数组中的逆序对)

    // 面试题51:数组中的逆序对 // 题目:在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组 // 成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. #include &l ...