java的同步实现
在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的同步实现的更多相关文章
- java多线程-同步块
Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java 同步块用来避免竞争.本文介绍以下内容: Java 同步关键字(synchronzied) 实例方法同步 ...
- 一篇搞定RSA加密与SHA签名|与Java完全同步
基础知识 什么是RSA?答:RSA是一种非对称加密算法,常用来对传输数据进行加密,配合上数字摘要算法,也可以进行文字签名. RSA加密中padding?答:padding即填充方式,由于RSA加密算法 ...
- Java多线程同步问题的探究
一.线程的先来后到——问题的提出:为什么要有多线程同步?Java多线程同步的机制是什么? http://www.blogjava.net/zhangwei217245/archive/2010/03/ ...
- java 线程同步 原理 sleep和wait区别
java线程同步的原理java会为每个Object对象分配一个monitor, 当某个对象(实例)的同步方法(synchronized methods)被多个线程调用时,该对象的monitor将负责处 ...
- Java线程同步_1
Java线程同步_1 synchronized 该同步机制的的核心是同步监视器,任何对象都可以作为同步监视器,代码执行结束,或者程序调用了同步监视器的wait方法会导致释放同步监视器 synchron ...
- 转:关于JAVA多线程同步
转:http://lanvis.blog.163.com/blog/static/26982162009798422547/ 因为需要,最近关注了一下JAVA多线程同步问题.JAVA多线程同步主要依赖 ...
- java多线程同步
一篇好文:java多线程机制同步原则 概括起来说,Java 多线程同步机制主要包含如下几点:1:如果一个类包含一个或几个同步方法,那么由此类生成的每一个对象都配备一个队列用来容纳那些等待执行同步的线程 ...
- java多线程——同步块synchronized详解
Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java同步块用来避免竞争.本文介绍以下内容: Java同步关键字(synchronzied) 实例方法同步 静 ...
- Java线程同步之一--AQS
Java线程同步之一--AQS 线程同步是指两个并发执行的线程在同一时间不同时执行某一部分的程序.同步问题在生活中也很常见,就比如在麦当劳点餐,假设只有一个服务员能够提供点餐服务.每个服务员在同一时刻 ...
- java 轻量级同步volatile关键字简介与可见性有序性与synchronized区别 多线程中篇(十二)
概念 JMM规范解决了线程安全的问题,主要三个方面:原子性.可见性.有序性,借助于synchronized关键字体现,可以有效地保障线程安全(前提是你正确运用) 之前说过,这三个特性并不一定需要全部同 ...
随机推荐
- 【C#】委托中的匿名函数与lambda
将方法作为方法的参数 委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使 ...
- facebook api call——error
Error Codes send-api error-codes whatsapp api errors marketing-api error-reference graph-api/using-g ...
- BZOJ 1037: [ZJOI2008]生日聚会Party(区间dp)
http://www.lydsy.com/JudgeOnline/problem.php?id=1037 题意: 思路: 四维数组进行dp,dp[i][j][a][b]表示进行到第i个座位时已经有j个 ...
- C# widget
Invoke(Delegate)的用法: //例如,要实时update窗体.如果在另一个线程中update,那么可以直接update(可以不在新线程中):也可以在Delegate中给出upate,然后 ...
- java虚拟机知识和 内存 堆(heap)、栈(stack)和方法区(method)
1.虚拟机实例 每个java程序都运行在自己的java虚拟机实例中,运行三个java程序就会得到三个虚拟机实例 守护线程(虚拟机自己使用,比如说执行垃圾收集任务的线程) 非守护线程(java初试线程, ...
- React native中的组建通知通信:
有这么一个需求,在B页面pop()回到A页面,需要A页面执行刷新,那么我们可以采用以下方法: 1:在A页面Push到B页面中,加上一个A页面中的刷新函数做为参数,然后在B页面中在pop()函数封装后通 ...
- codeforces 768E Game of Stones
题目链接:http://codeforces.com/problemset/problem/768/E NIM游戏改版:对于任意一堆,拿掉某个次数最多只能一次. 对于一堆石头数量为$X$.找到一个最小 ...
- 启动总是提示:Process finished with exit code 0
1.端口冲突检查端口号 2.缺少web启动依赖 <dependency> <groupId>org.springframework.boot</groupId> & ...
- c++ demo
#include "stdafx.h" #include <boost\version.hpp> #include <boost\config.hpp> # ...
- jmeter线程组之间传参
背景介绍: 使用jmeter做登录和搜索接口的测试: 登录接口请求头为:Content-Type: application/x-www-form-urlencoded; charset=UTF-8 搜 ...