位置: 建议127: Lock与synchronized是不一样的

首先在概念上纠正这一篇内容:

援引Java源码中关于ReentrantLock的开篇说明:

* A reentrant mutual exclusion {@link Lock} with the same basic
 * behavior and semantics as the implicit monitor lock accessed using
 * {@code synchronized} methods and statements, but with extended
 * capabilities.

根据说明: 两个加锁方式是具有相同的基础行为和语义的,仅仅是表现形式上和功能扩展性方面的差别,所以该建议理论是错误的.

以下代码段的执行差异和原作者的解释错误主要出现在以下几个方面:

1.  ReentrantLock和synchronized 都是对象级所,而没有一个是类级的,因此都只能作用到代码所影响的具体对象上去.

  如 synchronized public void read(){

    // some executing code region

  } 其实是隐式锁定了this;

  等价于:

  Lock lock = new ReentrantLock();

  public void read(){

    lock.lock();

    try{

      // some executing code region

    }finally{

      lock.unlock();

    }

  }

  两者的区别是一个monitorthis, 一个monitor lock对象.

比较特殊的情况是:

synchronized publi static execute(){

  

}

该类对象锁定的是 .class对象.

下文中的不一致性主要出现在对"A"的synchronized锁定上,

常量字符串对象在整个生命周期内是全局唯一的,因此,对"A"的所是全局生效的,不仅仅在次类内部,及时全局任何对synchronized("A")都会产生同步效果,这里违反了封闭原则,因此具有巨大的编程风险.

援引代码错误:

该篇引用了两段代码来说明两种方式的行为不一致性.

在这里简单地列举并指出问题所在:

class1 : lock

/*****************************************************************************/

class Task {

  public void doSomething(){

    try{

      Thread.sleep(2000);

    }catch(Exception e){

      // 异常处理

    }

    StringBuilder sb = new StringBuilder();

    // 线程名称:

    sb.append(" 线程名称: " + Thread.currentThread().getName());

    // 运行时间戳

    sb.append(",执行时间: " + Calendar.getInstance().get(13) + " s");

    System.out.println(sb.toString());

  }

}

/****************************************************************************/

class TaskWithLock extends Task implements Runnable{

  private final Lock lock = new ReentrantLock();

  @Override

  public void run(){

    try{

      // 开始锁定

      lock.lock();

      doSomething();

    }finally{

      // 释放锁

      lock.unlock();

    }

  }

}

/***************************************************************************/

class TaskWithSync extends Task implements Runnable{

  @Override

  public void run(){

    // 内部索

    synchronized("A"){

      doSomething();

    }

  }

}

public static void runTasks(Class<? extends Runnable> clazz) throws Exception {

  try{

  ExecutorService es = Executors.newCachedThreadPool();

  System.out.println("***开始执行" + clazz.getSimpleName() + " 任务已执行完毕-----------------\n");

  // 启动三个线程

  for ( int i=0; i<3 ; i++){

    es.submit(clazz.newInstance());

  }

  TimeUnit.SECONDS.sleep(10);

  System.out.println("--------" + clazz.getSimpleName() + " 任务执行完毕------\n");

  // 关闭执行器

  }finally{

    es.shutdown();

  }

}

秦晓波著的编写高质量代码-改善Java程序的151个建议一书中的线程解释错误.的更多相关文章

  1. 编写高质量代码改善java程序的151个建议——[1-3]基础?亦是基础

    原创地址:   http://www.cnblogs.com/Alandre/  (泥沙砖瓦浆木匠),需要转载的,保留下! Thanks The reasonable man adapts himse ...

  2. 博友的 编写高质量代码 改善java程序的151个建议

    编写高质量代码 改善java程序的151个建议 http://www.cnblogs.com/selene/category/876189.html

  3. 编写高质量代码改善java程序的151个建议——导航开篇

    2014-05-16 09:08 by Jeff Li 前言 系列文章:[传送门] 下个星期度过这几天的奋战,会抓紧java的进阶学习.听过一句话,大哥说过,你一个月前的代码去看下,慘不忍睹是吧.确实 ...

  4. 编写高质量代码:改善Java程序的151个建议 --[117~128]

    编写高质量代码:改善Java程序的151个建议 --[117~128] Thread 不推荐覆写start方法 先看下Thread源码: public synchronized void start( ...

  5. 编写高质量代码:改善Java程序的151个建议 --[106~117]

    编写高质量代码:改善Java程序的151个建议 --[106~117] 动态代理可以使代理模式更加灵活 interface Subject { // 定义一个方法 public void reques ...

  6. 编写高质量代码:改善Java程序的151个建议 --[78~92]

    编写高质量代码:改善Java程序的151个建议 --[78~92] HashMap中的hashCode应避免冲突 多线程使用Vector或HashTable Vector是ArrayList的多线程版 ...

  7. 编写高质量代码:改善Java程序的151个建议 --[65~78]

    编写高质量代码:改善Java程序的151个建议 --[65~78] 原始类型数组不能作为asList的输入参数,否则会引起程序逻辑混乱. public class Client65 { public ...

  8. 编写高质量代码:改善Java程序的151个建议 --[52~64]

    编写高质量代码:改善Java程序的151个建议 --[52~64] 推荐使用String直接量赋值 Java为了避免在一个系统中大量产生String对象(为什么会大量产生,因为String字符串是程序 ...

  9. 编写高质量代码:改善Java程序的151个建议 --[36~51]

    编写高质量代码:改善Java程序的151个建议 --[36~51] 工具类不可实例化 工具类的方法和属性都是静态的,不需要生成实例即可访 问,而且JDK也做了很好的处理,由于不希望被初始化,于是就设置 ...

随机推荐

  1. 修改DEDE系统数据库表前缀

    1,修改之前我们先备份下数据(哥们儿之前没有备份,我艹,害苦了),备份的操作过程是:网站后台------系统------数据库备份/还原-------然后按提交.默认保存的数据在data/backup ...

  2. PHP加密方式。 base!base!base!

    PHP中的加密方式有如下几种 1. MD5加密 string md5 ( string $str [, bool $raw_output = false ] ) 参数 str  --  原始字符串. ...

  3. java时间类型转换 JsonValueProcessor

    问题描述: java里面时间类型转换成json数据就成这样了:"createTime":{"date":30,"day":3,"h ...

  4. 查看识别hadoop是32位还是64位

    问题导读: 1.从哪些地方可以识别hadoop是32位还是64位?2.hadoop本地库在什么位置? 来源:about云 本文链接:http://www.aboutyun.com/thread-127 ...

  5. Tomcat 系统架构与设计模式之一

    Tomcat 系统架构与设计模式,第 1 部分: 工作原理 来自:http://www.ibm.com/developerworks/cn/java/j-lo-tomcat1/index.html 这 ...

  6. rsync(一):基本命令和用法

    以下是rsync系列篇: 1.1 说在前面的话 rsync官方网站: https://www.samba.org/ftp/rsync/rsync.html rsync是可以实现增量备份的工具.配合任务 ...

  7. 固定dll的加载基址的方法

    调试dll的时候会有一件事情比较烦人,就是dll加载的地址不会很固定(默认设置下编译的dll基址总是0x10000000,多个同基址的dll加载时,后面的肯定会被重定位),这给前后多次调试时对比分析结 ...

  8. Table View Programming Guide for iOS---(七)---Managing Selections

    Managing Selections 管理选择 When users tap a row of a table view, usually something happens as a result ...

  9. 斯坦福CS231n—深度学习与计算机视觉----学习笔记 课时4

    课时4 数据驱动的图像分类:K最邻与线性分类器(上) 图像分类之前,我们需要将图片转换成一张巨大的数字表单,然后从所有种类中,给这个表单选定一个标签. 为什么分类问题是个困难的问题:图像分类难点是,当 ...

  10. P4141 消失之物(背包)

    传送门 太珂怕了……为什么还有大佬用FFT和分治的…… 首先如果没有不取的限制的话就是一个裸的背包 然后我们考虑一下,正常的转移的话代码是下面这个样子的 ;i<=n;++i) for(int j ...