在java编程中,经常需要用到同步,而用得最多的也许是synchronized关键字了,下面看看这个关键字的用法。

因为synchronized关键字涉及到锁的概念,所以先来了解一些相关的锁知识。

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

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

java的对象锁和类锁:java的对象锁和类锁在锁的概念上基本上和内置锁是一致的,但是,两个锁实际是有很大的区别的,对象锁是用于对象实例方法,或者一个对象实例上的,类锁是用于类的静态方法或者一个类的class对象上的。我们知道,类的对象实例可以有很多个,但是每个类只有一个class对象,所以不同对象实例的对象锁是互不干扰的,但是每个类只有一个类锁。但是有一点必须注意的是,其实类锁只是一个概念上的东西,并不是真实存在的,它只是用来帮助我们理解锁定实例方法和静态方法的区别的。

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

  1. public class TestSynchronized
  2. {
  3. public void test1()
  4. {
  5. synchronized(this)
  6. {
  7. int i = 5;
  8. while( i-- > 0)
  9. {
  10. System.out.println(Thread.currentThread().getName() + " : " + i);
  11. try
  12. {
  13. Thread.sleep(500);
  14. }
  15. catch (InterruptedException ie)
  16. {
  17. }
  18. }
  19. }
  20. }
  21. public synchronized void test2()
  22. {
  23. int i = 5;
  24. while( i-- > 0)
  25. {
  26. System.out.println(Thread.currentThread().getName() + " : " + i);
  27. try
  28. {
  29. Thread.sleep(500);
  30. }
  31. catch (InterruptedException ie)
  32. {
  33. }
  34. }
  35. }
  36. public static void main(String[] args)
  37. {
  38. final TestSynchronized myt2 = new TestSynchronized();
  39. Thread test1 = new Thread(  new Runnable() {  public void run() {  myt2.test1();  }  }, "test1"  );
  40. Thread test2 = new Thread(  new Runnable() {  public void run() { myt2.test2();   }  }, "test2"  );
  41. test1.start();;
  42. test2.start();
  43. //         TestRunnable tr=new TestRunnable();
  44. //         Thread test3=new Thread(tr);
  45. //         test3.start();
  46. }
  47. }

上述的代码,第一个方法时用了同步代码块的方式进行同步,传入的对象实例是this,表明是当前对象,当然,如果需要同步其他对象实例,也不可传入其他对象的实例;第二个方法是修饰方法的方式进行同步。因为第一个同步代码块传入的this,所以两个同步代码所需要获得的对象锁都是同一个对象锁,下面main方法时分别开启两个线程,分别调用test1和test2方法,那么两个线程都需要获得该对象锁,另一个线程必须等待。

2、类锁的修饰(静态)方法和代码块:

  1. public class TestSynchronized
  2. {
  3. public void test1()
  4. {
  5. synchronized(TestSynchronized.class)
  6. {
  7. int i = 5;
  8. while( i-- > 0)
  9. {
  10. System.out.println(Thread.currentThread().getName() + " : " + i);
  11. try
  12. {
  13. Thread.sleep(500);
  14. }
  15. catch (InterruptedException ie)
  16. {
  17. }
  18. }
  19. }
  20. }
  21. public static synchronized void test2()
  22. {
  23. int i = 5;
  24. while( i-- > 0)
  25. {
  26. System.out.println(Thread.currentThread().getName() + " : " + i);
  27. try
  28. {
  29. Thread.sleep(500);
  30. }
  31. catch (InterruptedException ie)
  32. {
  33. }
  34. }
  35. }
  36. public static void main(String[] args)
  37. {
  38. final TestSynchronized myt2 = new TestSynchronized();
  39. Thread test1 = new Thread(  new Runnable() {  public void run() {  myt2.test1();  }  }, "test1"  );
  40. Thread test2 = new Thread(  new Runnable() {  public void run() { TestSynchronized.test2();   }  }, "test2"  );
  41. test1.start();
  42. test2.start();
  43. //         TestRunnable tr=new TestRunnable();
  44. //         Thread test3=new Thread(tr);
  45. //         test3.start();
  46. }
  47. }

类锁修饰方法和代码块的效果和对象锁是一样的,因为类锁只是一个抽象出来的概念,只是为了区别静态方法的特点,因为静态方法是所有对象实例共用的,所以对应着synchronized修饰的静态方法的锁也是唯一的,所以抽象出来个类锁。那么两个线程都需要获得该对象锁,另一个线程必须等待。

3、synchronized同时修饰静态和非静态方法:

  1. public class TestSynchronized
  2. {
  3. public synchronized void test1()
  4. {
  5. int i = 5;
  6. while( i-- > 0)
  7. {
  8. System.out.println(Thread.currentThread().getName() + " : " + i);
  9. try
  10. {
  11. Thread.sleep(500);
  12. }
  13. catch (InterruptedException ie)
  14. {
  15. }
  16. }
  17. }
  18. public static synchronized void test2()
  19. {
  20. int i = 5;
  21. while( i-- > 0)
  22. {
  23. System.out.println(Thread.currentThread().getName() + " : " + i);
  24. try
  25. {
  26. Thread.sleep(500);
  27. }
  28. catch (InterruptedException ie)
  29. {
  30. }
  31. }
  32. }
  33. public static void main(String[] args)
  34. {
  35. final TestSynchronized myt2 = new TestSynchronized();
  36. Thread test1 = new Thread(  new Runnable() {  public void run() {  myt2.test1();  }  }, "test1"  );
  37. Thread test2 = new Thread(  new Runnable() {  public void run() { TestSynchronized.test2();   }  }, "test2"  );
  38. test1.start();
  39. test2.start();
  40. //         TestRunnable tr=new TestRunnable();
  41. //         Thread test3=new Thread(tr);
  42. //         test3.start();
  43. }
  44. }

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

到这里,对synchronized的用法已经有了一定的了解。这时有一个疑问,既然有了synchronized修饰方法的同步方式,为什么还需要synchronized修饰同步代码块的方式呢?而这个问题也是synchronized的缺陷所在

synchronized的缺陷:当某个线程进入同步方法获得对象锁,那么其他线程访问这里对象的同步方法时,必须等待或者阻塞,这对高并发的系统是致命的,这很容易导致系统的崩溃。如果某个线程在同步方法里面发生了死循环,那么它就永远不会释放这个对象锁,那么其他线程就要永远的等待。这是一个致命的问题。

一个类的对象锁和另一个类的对象锁是没有关联的,当一个线程获得A类的对象锁时,它同时也可以获得B类的对象锁。

java的对象锁和类锁的更多相关文章

  1. Java锁Synchronized,对象锁和类锁举例

    Java的锁分为对象锁和类锁. 1. 当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内针对该对象的操作只能有一个线程得到执行.另一个线程必须 ...

  2. Java锁Synchronized对象锁和类锁区别

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

  3. Java对象锁和类锁全面解析(多线程synchronized关键字)

    最近工作有用到一些多线程的东西,之前吧,有用到synchronized同步块,不过是别人怎么用就跟着用,并没有搞清楚锁的概念.最近也是遇到一些问题,不搞清楚锁的概念,很容易碰壁,甚至有些时候自己连用没 ...

  4. java 对象锁和类锁的区别(转)

    java 对象锁和类锁的区别   转自; ) ); ; ) ); 上述的代码,第一个方法时用了同步代码块的方式进行同步,传入的对象实例是this,表明是当前对象,当然,如果需要同步其他对象实例,也不可 ...

  5. 【Thread】java线程之对象锁、类锁、线程安全

    说明: 1.个人技术也不咋滴.也没在项目中写过线程,以下全是根据自己的理解写的.所以,仅供参考及希望指出不同的观点. 2.其实想把代码的github贴出来,但还是推荐在初学的您多亲自写一下,就没贴出来 ...

  6. java线程同步以及对象锁和类锁解析(多线程synchronized关键字)

    一.关于线程安全 1.是什么决定的线程安全问题? 线程安全问题基本是由全局变量及静态变量引起的. 若每个线程中对全局变量.静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的:若有多个线 ...

  7. Java 中对象锁和类锁的区别? 关键字 Synchronized的用法?

    一  对象锁和类锁的关系 /* * 对象锁和[类锁] 全局锁的关系? 对象锁是用于对象实例方法,或者一个对象实例上的 this 类锁是用于类的静态方法或者一个类的class对象上的. Ag.class ...

  8. java的同步方法和同步代码块,对象锁,类锁区别

    /** * @author admin * @date 2018/1/12 9:48 * 作用在同一个实例对象上讨论 * synchronized同步方法的测试 * 两个线程,一个线程调用synchr ...

  9. Synchronized方法锁、对象锁、类锁区别

    synchronized,这个东西我们一般称之为”同步锁“,他在修饰代码块的时候需要传入一个引用对象作为“锁”的对象. 在修饰方法的时候,默认是当前对象作为锁的对象 在修饰类时,默认是当前类的Clas ...

随机推荐

  1. 自然语言交流系统 phxnet团队 创新实训 项目博客 (十四)

    项目技术借鉴报告: 一.服务器端(Server) 1.分词 分词使用的是庖丁分词.使用盘古分词词库和词素作为辅助.其中包括下载Jar包并且使用. 2.人工神经网络 以网上已有的初级网络为蓝图,结合机器 ...

  2. USB2.0学习笔记连载(十七):keil实现寄存器的配置及相关函数讲解(一)

    首先要实现对寄存器的配置,可以参考手册<Development kit  User Guide>,如下图所示: 此文件包含在 文件中.上述的应用文档详细介绍了如何利用KEIL实现对固件程序 ...

  3. sublime text 2使用方法

    笔者用过的一些软件用来写Verilog代码,比如notepad+,ultra,editplus等,近日在群里看到大家在讨论一个比较有意思的软件,sublime text,才发现有种相见恨晚的感觉,其实 ...

  4. MySQL 数据库 varchar 到底可以存多少个汉字,多少个英文呢?我们来搞搞清楚

    一.关于UTF-8 UTF-8 Unicode Transformation Format-8bit.是用以解决国际上字符的一种多字节编码. 它对英文使用8位(即一个字节) ,中文使用24位(三个字节 ...

  5. C++ 指针二维数组, C++二维指针数组笔记

    C++ 二维动态数组 一. 已知第一维 #include <iostream> using namespace std; int main(int argc, char const *ar ...

  6. 使用Photoshop实现弹簧字效果

    一.准备工作 软件环境:PhotoshopCS6 目的:使用路径实现弹簧字效果 二.实验步骤 1,新建画布 2,背景改为黑色,快捷键 Alt+Delete 3,键入文字,发现文字显示不出来,这时选择左 ...

  7. JavaScript数据去掉空值

    js数组中过滤掉false, null, 0, "", undefined, and NaN值的方法 对于 false,null,0,undefiend,NaN直接取!得到的都是t ...

  8. R 语言消除pdf图片的空白

    pdf 函数中,有一个参数onefile ,  默认值为TRUE, 表示每张图片占用pdf 中的一页 当遇到pdf的前几页为空白时,是因为画图的代码产生了几张空白的图片 如果要消除前面的空白,只需要设 ...

  9. Linux入门教程:如何检查Linux系统的最后重启时间

    问题: 是否有一个命令可以快速地检查系统已经运行了多久? 也就是我怎么知道Linux系统最后的重启时间? 有许多方法来查询系统最后的重启时间. 方法一 第一种方法是使用last命令. $ last r ...

  10. 惊艳的HTML5动画特效及源码

    今天我们要来分享一些很酷的HTML5动画演示,HTML5的强大之处在于它可以利用canvas的特性来绘制很多普通网页无法完成的图形和动画,canvas就像一块超级画板,在上面不仅可以实现平面图形,而且 ...