在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. MFC中UpdateData()函数的使用

    UpdateData(true); 用窗体上控件中的内容来更新和控件相关连的变量的值(只能更新value类型的变量) 例如:你在你的窗体中有一个Edit控件,为这个控件关联了CString类型的变量m ...

  2. easyui datagrid设置fit: true后,页面显示不全的情况

    跟工具栏有关 <div id="tb"> <div style="float:left;"> <a href="#&qu ...

  3. 《Scrum实战》读书会作业01 - 用知行视角总结现在或者过去的一个项目

    下面是<Scrum实战>读书会的第1个作业,主要是用知行视角来总结回顾现在或者过去的一个项目. 项目背景 2011年初,我做的项目是一个搜索引擎相关的项目,这个项目为公司在全球范围内的金融 ...

  4. 【CSS3】好玩的动画线框

    <div class="box">动画选框</div> .box{ width:300px; height:100px; border:1px dotted ...

  5. Ubuntu 地址导航栏修改为显示路径及如何恢复原模式?

    在Ubuntu中,文件位置默认不是和Windows地址栏一样的(位置项),而是显示是路径名称组合(路径栏),这对于文件路径的获得复制很不方便.比如,获得某个文件德 路径,如果是地址栏,直接复制一下就可 ...

  6. linux查找文件夹命令

    查找命令: 查找根目录下查找文件夹名称叫www.91cnm.com的目录地址 find / -name www.91cnm.com -d 1 查找/var/www/目录下叫index.php的文件 f ...

  7. 【Html】Clipboard.js 实现点击复制,剪切板操作

    可以使用cdn 或者直接下载 设置好引用路径(百度云下载) <script type="text/javascript" src="./dist/clipboard ...

  8. 转载:AOP那点事

    原作者:黄勇 博客地址:https://my.oschina.net/huangyong/blog/161338 又是一个周末,刚给宝宝喂完牛奶,终于让她睡着了.所以现在我才能腾出手来,坐在电脑面前给 ...

  9. 纯CSS3实现的顶部社会化分享按钮

    今天要分享一款纯CSS3实现的社会化分享按钮,它放置在网页的顶部,你可以选择将它固定在网页顶部,这样对用户分享内容就十分方便.这些社会化分享按钮的图标文件来自google和bootstrap的字体文件 ...

  10. 用外部物理路由器时与外部dhcp服务时怎样使用metadata服务(by quqi99)

    作者:张华  发表于:2015-12-31版权声明:能够随意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 ( http://blog.csdn.net/quqi99 ) 用外部 ...