java同步和互斥【用具体程序说明】

 
         所有对象都自动含有单一的锁,也就是所有对象都有且只有唯一的锁,所以当某个任务(线程)访问一个类A中含有sycnhronized的方法是,那么在这个线程从该方法返回之前(也就是该方法在当前线程执行完之前),类A中的其他被该关键字标记的方法在其他的线程中都会被阻塞。
            通俗点说就是,当调用A的含有synchronized的方法是,A会被枷锁,此时A中其他含有synchronized方法只有等到前一个方法调用完毕释放了锁才能被调用

具体说明见另一篇博客<<java同步和互斥【相关原理】》

下面看看具体的程序,其中,Timer中的字段num是共享资源

  1. package com.bankht.synchronize;
  2. public class TestSync implements Runnable {
  3. Timer timer = new Timer();
  4. public static void main(String[] args) {
  5. TestSync test = new TestSync();
  6. Thread t1 = new Thread(test);
  7. Thread t2 = new Thread(test);
  8. t1.setName("t1");
  9. t2.setName("t2");
  10. t1.start();
  11. t2.start();
  12. }
  13. public void run() {
  14. timer.add(Thread.currentThread().getName());
  15. }
  16. }
  17. class Timer {
  18. private static int num = 0;
  19. public void add(String name) {
  20. num++;
  21. try {
  22. Thread.sleep(1);
  23. } catch (InterruptedException e) {
  24. }
  25. System.out.println(name + ", 你是第" + num + "个使用timer的线程");
  26. }
  27. }
  1. 由于没有同步,所以运行结果如下所示

t1, 你是第2个使用timer的线程

t2, 你是第2个使用timer的线程

也就是说当线程一运行到num++的时候被打线程2打断了,由于java中递增和递减操作均不是原子操作,所以本程序中即使没有调用sleep,也会出现这种被打断的情况

下面看看同步的效果

  1. public void add(String name) {
  2. synchronized (this) {//同步
  3. num++;
  4. try {
  5. Thread.sleep(1000);
  6. } catch (InterruptedException e) {
  7. }
  8. System.out.println(name + ", 你是第" + num + "个使用timer的线程");
  9. }
  10. }

这样运行结果就会出是正确的

t1, 你是第1个使用timer的线程

t2, 你是第2个使用timer的线程

但是,下面为了说明问题把TestSync里面的run方法改成如下所示

  1. public void run() {
  2. /
  3. time.add(Thread.currentThread().getName());
  4. try {
  5. Thread.sleep(1000);//为了显示结果,让其睡眠一秒
  6. } catch (InterruptedException ex) {
  7. Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);
  8. }
  9. System.out.println(Thread.currentThread().getName() + "----");
  10. }

那么在此运行就是

t1, 你是第1个使用timer的线程

t2, 你是第2个使用timer的线程

t1--------

t2--------

而不是你所想象的

t1, 你是第1个使用timer的线程
t1----
t2, 你是第2个使用timer的线程
t2----

原因就是在线程t1在睡眠的时候,线程t2切换进来,执行了一次,怎样得到正确的结果呢,下面把TestSync里面的run方法做如下改进就可以得到上面预期的结果

  1. public void run() {
  2. synchronized(time){
  3. time.add(Thread.currentThread().getName());
  4. try {
  5. Thread.sleep(3000);
  6. } catch (InterruptedException ex) {
  7. Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);
  8. }
  9. System.out.println(Thread.currentThread().getName() + "----");
  10. }
  11. }

因为t1先获得time的锁,所以在执行完run里面的同步块之前,即使sleep(),t2也不会执行,因为t2没有获得time的锁,且sleep()操作也不释放锁(这也是和wait的巨大区别)

附录:TestSync.java全部代码

  1. package com.bankht.synchronize;
  2. import java.util.logging.Level;
  3. import java.util.logging.Logger;
  4. public class TestSync implements Runnable {
  5. Timer timer = new Timer();
  6. public static void main(String[] args) {
  7. TestSync test = new TestSync();
  8. Thread t1 = new Thread(test);
  9. Thread t2 = new Thread(test);
  10. t1.setName("t1");
  11. t2.setName("t2");
  12. t1.start();
  13. t2.start();
  14. }
  15. //  public void run() {
  16. //      timer.add(Thread.currentThread().getName());
  17. //  }
  18. //   public void run() {
  19. //       timer.add(Thread.currentThread().getName());
  20. //            try {
  21. //                Thread.sleep(1000);//为了显示结果,让其睡眠一秒
  22. //            } catch (InterruptedException ex) {
  23. //                Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);
  24. //            }
  25. //          System.out.println(Thread.currentThread().getName() + "----");
  26. //        }
  27. public void run() {
  28. synchronized(timer){
  29. timer.add(Thread.currentThread().getName());
  30. try {
  31. Thread.sleep(3000);
  32. } catch (InterruptedException ex) {
  33. Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);
  34. }
  35. System.out.println(Thread.currentThread().getName() + "----");
  36. }
  37. }
  38. }
  39. class Timer {
  40. private static int num = 0;
  41. //  public void add(String name) {
  42. //
  43. //      num++;
  44. //      try {
  45. //          Thread.sleep(1000);
  46. //      } catch (InterruptedException e) {
  47. //      }
  48. //      System.out.println(name + ", 你是第" + num + "个使用timer的线程");
  49. //
  50. //  }
  51. public void add(String name) {
  52. synchronized (this) {// 同步
  53. num++;
  54. try {
  55. Thread.sleep(1000);
  56. } catch (InterruptedException e) {
  57. }
  58. System.out.println(name + ", 你是第" + num + "个使用timer的线程");
  59. }
  60. }
  61. }

java同步和互斥【用具体程序说明】的更多相关文章

  1. 【Java并发基础】并发编程领域的三个问题:分工、同步和互斥

    前言 可以将Java并发编程抽象为三个核心问题:分工.同步和互斥. 这三个问题的产生源自对性能的需求.最初时,为提高计算机的效率,当IO在等待时不让CPU空闲,于是就出现了分时操作系统也就出现了并发. ...

  2. 监视锁——Java同步的基本思想

    翻译人员: 铁锚翻译时间: 2013年11月13日原文链接: Monitors – The Basic Idea of Java synchronization如果你上过操作系统课程,你就知道监视锁( ...

  3. 死磕 java同步系列之zookeeper分布式锁

    问题 (1)zookeeper如何实现分布式锁? (2)zookeeper分布式锁有哪些优点? (3)zookeeper分布式锁有哪些缺点? 简介 zooKeeper是一个分布式的,开放源码的分布式应 ...

  4. 死磕 java同步系列之ReentrantReadWriteLock源码解析

    问题 (1)读写锁是什么? (2)读写锁具有哪些特性? (3)ReentrantReadWriteLock是怎么实现读写锁的? (4)如何使用ReentrantReadWriteLock实现高效安全的 ...

  5. Java同步与异步

    一.关键字: thread(线程).thread-safe(线程安全).intercurrent(并发的) synchronized(同步的).asynchronized(异步的). volatile ...

  6. 转载自~浮云比翼:Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥)

    Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥)   介绍:什么是线程,线程的优点是什么 线程在Unix系统下,通常被称为轻量级的进程,线程虽然不是进程,但却可 ...

  7. exec函数族,守护进程,线程同步和互斥

    2015.3.2 进程和程序有三点不同:1,存在位置不同,程序:硬盘,磁盘.进程:内存2. 程序是静态的,进程是动态的 执行./a.out -->bash->bash程序调用fork()- ...

  8. Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥)

    介绍:什么是线程,线程的优点是什么 线程在Unix系统下,通常被称为轻量级的进程,线程虽然不是进程,但却可以看作是Unix进程的表亲,同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间, ...

  9. Windows下C++多线程同步与互斥简单运用

    1.  互斥量,Mutex #include <Windows.h> #include <iostream> using namespace std; DWORD WINAPI ...

随机推荐

  1. 20175212童皓桢 Java实验二-面向对象程序设计实验报告

    20175212童皓桢 Java实验二-面向对象程序设计实验报告 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设 ...

  2. eXosip2 编译安装

    eXosip2-3.6.0 编译安装 刚开始我使用了 下面文章介绍里版本  我以为不支持tcp 其实是因为我服务端的端口 没有写对. https://www.cnblogs.com/elisha-bl ...

  3. mysql 自定义插件调试

    # 创建表的stack frame #0: 0x000000011d11f58a ha_spartan.so`Spartan_data::create_table(this=0x00007f9fc13 ...

  4. 转载(略有修改):Windows 8的承载网络设置方法(w8 创建无线网络/ap)

    第一步.查看电脑是否支持网络共享 在命令提示符(打开方式看文章最后)中输入:netsh wlan show drivers,然后回车. 找到"支持的承载网络"一项,如果后面显示的是 ...

  5. 大量数据的excel导出

    对于大型excel的创建且不会内存溢出的,就只有SXSSFWorkbook了.它的原理很简单,用硬盘空间换内存(就像hash map用空间换时间一样). private void writeToAla ...

  6. iSlide——图标库、图示库的用法

    iSlide中,有一个“图示库”功能,主要功能是同时排列多块文字或多张图片.单击插图库,会弹出一个新的对话框.从中,可以选择权限.分类.数量数据和样式,也可以直接搜索.   下面就举一个例子:我要开一 ...

  7. MOS管应用概述(四):基本参数

    mos管的基本参数,大家熟悉的必然是Ids电流,Ron导通电阻,Vgs的阈值电压,Cgs.Cgd.Cds这几项,然而在高速应用中,开关速度这个指标比较重要.<ignore_js_op> 上 ...

  8. unity重写软键盘for Android NGUI

    一 原因 以为某些原因,需要重写Unity游戏中Android的软键盘的样式,然而unity对android和ios的ios的软键盘都有封装,在Unity中TouchScreenKeyboard.Op ...

  9. Possibly two send backs are happening for the same request

    错误 wso2 WARN {org.apache.synapse.transport.passthru.SourceHandler} -  Illegal incoming connection st ...

  10. Excel身份证验证,身份证校验公式

    =IF(LEN(Q4)=0,"空",IF(LEN(Q4)=15,"老号",IF(LEN(Q4)<>18,"位数不对",IF(CH ...