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

最新文章

  1. Yii 字段验证
  2. 【GoLang】golang中可以直接返回slice吗?YES
  3. JQuery学习之操作CSS
  4. python核心编程第六章练习6-14
  5. apache安装后编译新模块
  6. hadoop 2.4 伪分布式模式
  7. Unity中HDR外发光的使用
  8. html --- ajax --- javascript --- 简单的封装
  9. gridview_RowCommand 获取当前行中的控件
  10. Sublime Text 3配置与vim模式(待完整)
  11. Java文件操作源码大全
  12. 开源日志系统 log4c 使用心得+总结
  13. C#操作Cookie
  14. myeclipse的常用快捷键
  15. ReactNative布局样式总结
  16. mybatis自动生成mapper,dao映射文件
  17. github远程仓库初始化配置
  18. EFI系统引导的一些零碎知识点
  19. 数据库if判断语句
  20. Android 自定义弹出框带EditText

热门文章

  1. 搭建git 服务器
  2. (zhuan) Attention in Neural Networks and How to Use It
  3. Perceptual Losses for Real-Time Style Transfer and Super-Resolution and Super-Resolution 论文笔记
  4. 【ASP.NET】System.Web.Routing - HttpMethodConstraint Class
  5. QLineEdit响应回车时避免Button同时响应
  6. numa.h:No such file or directory 解决方法
  7. 无法启动此程序,因为计算机中丢失api-ms-win-crt-runtime-|1-1-0.dll
  8. JavaScript(ES5)知识点梳理
  9. data:image/png;base64 上传图像将图片转换成base64格式
  10. 【BZOJ】3926: [Zjoi2015]诸神眷顾的幻想乡