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

位置: 建议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();

  }

}

时间: 2024-10-27 06:14:30

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

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

原创地址:   http://www.cnblogs.com/Alandre/  (泥沙砖瓦浆木匠),需要转载的,保留下! Thanks The reasonable man adapts himself to the world;the unreasonable one persists in trying to adapt the world to himself. -萧伯纳 相信自己看得懂就看得懂了,相信自己能写下去,我就开始写了.其实也简单-泥沙砖瓦浆木匠 Written In The

转载-------编写高质量代码:改善Java程序的151个建议(第1章:JAVA开发中通用的方法和准则___建议1~5)

阅读目录 建议1:不要在常量和变量中出现易混淆的字母 建议2:莫让常量蜕变成变量 建议3:三元操作符的类型务必一致 建议4:避免带有变长参数的方法重载 建议5:别让null值和空值威胁到变长方法              The reasonable man adapts himself to the world; The unreasonable one persists in trying to adapt the world himself. 明白事理的人使自己适应世界:不明事理的人想让世

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

2014-05-16 09:08 by Jeff Li 前言 系列文章:[传送门] 下个星期度过这几天的奋战,会抓紧java的进阶学习.听过一句话,大哥说过,你一个月前的代码去看下,惨不忍睹是吧.确实,人和代码一样都在成长,都在变好当中.有时候只是实现功能的编程,长进不了呀. 博客提供的好处就可以交流,讨论的学习方法你们应该知道. 在这里,我会陆陆续续的进行对<编写高质量代码改善java程序的151个建议>看法,希望大家点击交流. 正文 看这本书原因   1.项目做的只是实现功能,然而没有好好

编写高质量代码改善java程序的151个建议——[110-117]异常及Web项目中异常处理

原创地址:http://www.cnblogs.com/Alandre/(泥沙砖瓦浆木匠),需要转载的,保留下! 文章宗旨:Talk is cheap show me the code. 大成若缺,其用不弊.大盈若冲,其用不穷.  <道德经-老子>最完满的东西,好似有残缺一样,但它的作用永远不会衰竭:最充盈的东西,好似是空虚一样,但是它的作用是不会穷尽的 Written In The Font 摘要: 异常处理概述 学习内容: 建议110: 提倡异常封装 建议111: 采用异常链传递异常 建议

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

编写高质量代码:改善Java程序的151个建议 --[52~64] 推荐使用String直接量赋值 Java为了避免在一个系统中大量产生String对象(为什么会大量产生,因为String字符串是程序中最经常使用的类型),于是就设计了一个字符串池(也叫作字符串常量池,String pool或String Constant Pool或String Literal Pool),在字符串池中容纳的都是String字符串对象,它的创建机制是这样的:创建一个字符串时,首先检查池中是否有字面值相等的字符串,

编写高质量代码:改善Java程序的151个建议(第1章:JAVA开发中通用的方法和准则___建议11~15)

建议11:养成良好习惯,显示声明UID 我们编写一个实现了Serializable接口(序列化标志接口)的类,Eclipse马上就会给一个黄色警告:需要添加一个Serial Version ID.为什么要增加?他是怎么计算出来的?有什么用?下面就来解释该问题. 类实现Serializable接口的目的是为了可持久化,比如网络传输或本地存储,为系统的分布和异构部署提供先决条件支持.若没有序列化,现在我们熟悉的远程调用.对象数据库都不可能存在,我们来看一个简单的序列化类: 1 import java

转载--编写高质量代码:改善Java程序的151个建议(第1章:JAVA开发中通用的方法和准则___建议16~20)

阅读目录 建议16:易变业务使用脚本语言编写 建议17:慎用动态编译 建议18:避免instanceof非预期结果 建议19:断言绝对不是鸡肋 建议20:不要只替换一个类 回到顶部 建议16:易变业务使用脚本语言编写 Java世界一直在遭受着异种语言的入侵,比如PHP,Ruby,Groovy.Javascript等,这些入侵者都有一个共同特征:全是同一类语言-----脚本语言,它们都是在运行期解释执行的.为什么Java这种强编译型语言会需要这些脚本语言呢?那是因为脚本语言的三大特征,如下所示:

编写高质量代码:改善Java程序的151个建议(第6章:枚举和注解___建议88~92)

建议88:用枚举实现工厂方法模式更简洁 工厂方法模式(Factory Method Pattern)是" 创建对象的接口,让子类决定实例化哪一个类,并使一个类的实例化延迟到其它子类".工厂方法模式在我们的开发中经常会用到.下面以汽车制造为例,看看一般的工厂方法模式是如何实现的,代码如下: 1 //抽象产品 2 interface Car{ 3 4 } 5 //具体产品类 6 class FordCar implements Car{ 7 8 } 9 //具体产品类 10 class B

编写高质量代码:改善Java程序的151个建议(第3章:类、对象及方法___建议36~40)

建议36:使用构造代码块精简程序 什么叫做代码块(Code Block)?用大括号把多行代码封装在一起,形成一个独立的数据体,实现特定算法的代码集合即为代码块,一般来说代码快不能单独运行的,必须要有运行主体.在Java中一共有四种类型的代码块: 普通代码块:就是在方法后面使用"{}"括起来的代码片段,它不能单独运行,必须通过方法名调用执行: 静态代码块:在类中使用static修饰,并用"{}"括起来的代码片段,用于静态变量初始化或对象创建前的环境初始化. 同步代码块