在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. 第一章(欢迎进入node.js世界)

    本章内容 1:Node.js是什么 2:服务器端javascript 3:node的异步和事件触发本质 4:node为谁而生 5:node程序示例 1.1 node.js他的首次亮相是在2009年,非 ...

  2. Nuget CsvHelper 的使用

    CsvHelper:nuget地址 csv导出类||生成类 public class CSVHeader { public string head1 { get; set; } public stri ...

  3. HDU 5452 Minimum Cut(LCA)

    http://acm.hdu.edu.cn/showproblem.php?pid=5452 题意: 有一个连通的图G,先给出图中的一棵生成树,然后接着给出图中剩余的边,现在要删除最少的边使得G不连通 ...

  4. C#端加载数据库,Combobox与Node控件绑定数据源demo示例

    最近一直在做网页.用的js比较多,最近需要做一个C#相关的demo,一开始还有点不适应,写了几句有点感觉了 本篇博客的主要内容是C#怎么读取数据库文件里的数据以及相关控件如何绑定数据源,所做的Demo ...

  5. Docker个人理解总结

    最新在学习Docker,记录下自己对Docker的理解. 一.Docker是什么? 1. Docker是一个能够把开发的应用程序自动部署到容器的开源引擎. 2.Docker使用Google公司推出的G ...

  6. 安装 Python-Client

    有多种安装Python-Client的方法: 第一种 Install from PyPi, as 'Appium-Python-Client'. >pip install Appium-Pyth ...

  7. go 获取网址html 源码

    // Sample program to show how to write a simple version of curl using // the io.Reader and io.Writer ...

  8. SQL Server DATEADD() 函数及实际项目应用注意事项

    1. DATEADD() 函数的解释和语法分析 DATEADD() 函数在日期中添加或减去指定的时间间隔. 语法: DATEADD(datepart,number,date) date 参数是合法的日 ...

  9. [JS]给String对象添加方法,使传入的字符串字符之间以空格分开输出

    看到一个这样子的面试题: 给String对象添加一个方法,传入一个string类型的参数,然后将string的每一个字符间加空格返回,例如:addSpace("hello world&quo ...

  10. 学习笔记18—circos应用集

    一.在线画图(行列分别最大为75) 相信大家都听说过circos图,但是亲自画过的人可能就很少,这主要因为软件的安装和使用稍微有一点麻烦.其实,circos图也是可以在线绘制的,这样就简单多了!一起来 ...