java核心技术卷一

java核心技术卷一



java基础类型

整型

数据类型 字节数 取值范围
int 4 +_2^4*8-1
short 2 +_2^2*8-1
long 8 +_2^8*8-1
byte 1 -128-127
     

浮点类型

数据类型 字节数 取值范围 小数位数
float 4 10^-38~10^38和-10^-38~-10^38 小数位数6-7
double 4 10^-308~10^308和-10^-308~-10^308 15位小数
       

boolean 类型和char 类型

java字符串

不可变字符串

    JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池,字符串常量池存
在于堆内存中的永久代。

1、StringBuilder与 StringBuffer:StringBuilder:线程非安全的,StringBuffer:线程安全的。
2、String.intern 方法

深入解析String#intern: http://tech.meituan.com/in_depth_understanding_string_intern.html

java自动装箱与对象包装器

    java中基础类型都有对应的包装器,装箱类型Integer,Long,Double,Short,Float,Byte,Character,Void,Boolean。

java集合

  • ArrayList 动态数组,动态的增加和缩减索引序列
  • LinkedList 链表集合,在任意位置高效的插入和删除的有序序列
  • ArrayDeque 用循环数组实现的双端队列
  • Hashset 无重复元素的无序列表
  • TreeSet
    有序集(二叉树)
  • EnumSet 枚举类型集
  • LinkedHashSet 有序的HashSet
  • HashMap 字典
  • TreeMap 有序映射表

java泛型

    java与c#一样,都存在泛型的概念,及类型的参数化。java中的泛型是在jdk5.0后出现的,但是java中的泛型与C#中的泛型是有本质区别的,首先从集合类型上来说,java 中的ArrayList<Integer>和ArrayList<String>是同一个类型,在编译时会执行类型擦除,及java中的类型是伪泛型,伪泛型将会在后面介绍,其次,对于像集合中添加基本类型的数据时,例如int,会首先将int转化成Integer对象,即我们通常所说的装箱操作,在取出元素的时候需要将Interger对象转换成int值类型,即拆箱操作。而在c#中,List<int>和List<string>是不同的类型,泛型参数在编译后会是一个占位符,并没有被擦除,在运行时被赋予正真的类型,它们在系统运行期生成,有自己的虚方法表和类型数据,这种实现称为类型膨胀(针对类型膨胀,即时编译器已经做了很多的优化工作来解决这一问题),这就是所谓的真泛型。与此同时,在对集合中添加基本元素如int时,不需要装箱操作,取出元素时不需要拆箱操作,因此,性能上较java的集合泛型要好。
java中泛型的引入主要是为了解决两个方面的问题:1.集合类型元素在运行期出现类型装换异常,增加编译时类型的检查,2. 解决的时重复代码的编写,能够复用算法。下面通过例子来说明编译器的类型检查。

java多线程

java 线程的几种状态

  • New(新创建)
  • Runnable(可运行)
  • Blocked(被阻塞)
  • Waiting(等待) 不占用CPU时间
  • Timed waiting(计时等待)
  • Terminated(被终止)
      BLOCKED是指线程正在等待获取锁;WAITING是指线程正在等待其他线程发来的通知(notify),收到通知后,可能会顺序向后执行(RUNNABLE),也可能会再次获取锁,进而被阻塞住(BLOCKED)。
    

    一个线程new 出来处于new的状态,当线程调用start方法,线程处于runnable 状态,当线程试图获取其他线程独占的资源时,线程进入blocked阻塞状态,当线程shleep方法调用或者试图获取条件锁等待其他线程唤醒则处于等待(waiting)状态。

      线程终止有两种情况,一种是正常终止,比如调用Thread.join 方法,一种是异常终止,程序发生未处理的异常。
    

    请注意,Thread.stop() 方法已弃用,他会强制终止一个线程和子线程,可能造成数据未能同步或者资源未释放等异常。

java线程优先级

    java线程的优先级根据不同的虚拟机映射到不同不同的操作系统优先级,子线程继承主线程的优先级。

java 线程同步

    当竞态条件产生时,java有两种机制防止对象被并发访问的干扰。
  • ReentrantLock 公平锁 的lock(), unlock() 方法用于锁定和解锁代码片段。
  • Condition 条件锁 比如有界缓冲区的实现:
--------------------------------------------------------------------------------
    class BoundedBuffer {
    final Lock lock = new ReentrantLock();//锁对象
    final Condition notFull  = lock.newCondition();//写线程条件
    final Condition notEmpty = lock.newCondition();//读线程条件   

    final Object[] items = new Object[100];//缓存队列
    int putptr/*写索引*/, takeptr/*读索引*/, count/*队列中存在的数据个数*/;  

    public void put(Object x) throws InterruptedException {
        lock.lock();
        try {
        while (count == items.length)//如果队列满了
            notFull.await();//阻塞写线程
        items[putptr] = x;//赋值
        if (++putptr == items.length) putptr = 0;//如果写索引写到队列的最后一个位置了,那么置为0
        ++count;//个数++
        notEmpty.signal();//唤醒读线程
        } finally {
        lock.unlock();
        }
    }  

    public Object take() throws InterruptedException {
        lock.lock();
        try {
        while (count == 0)//如果队列为空
            notEmpty.await();//阻塞读线程
        Object x = items[takeptr];//取值
        if (++takeptr == items.length) takeptr = 0;//如果读索引读到队列的最后一个位置了,那么置为0
        --count;//个数--
        notFull.signal();//唤醒写线程
        return x;
        } finally {
        lock.unlock();
        }
    }
    }
--------------------------------------------------------------------------------
  • synchronized关键字

    公平锁和条件锁提供了相当细粒度的线程同步控制操作能力,在java1.0开始,每个对象都有一个内部锁,我们可以通过synchronized 关键字声明一个同步方法或者同步代码块。当然他也不能提供一些细粒度的操作能力,比如中断一个正在试图获取锁的线程, 设置锁的阻塞时长,单一的获得锁的条件等。

  • volatile 与易失构造

    1、多核处理器能够在寄存器或者本地内存缓冲区中保存内存的值,不同的处理器可能从内存中读到不同的值

    2、编译器根据优化场景可能改变指令的执行顺序,编译器假定内存的值只有在显示修改内存的指令执行时内存的值才发生改变,但是另一个线程 可能正在修改内存的值。

理解场景=> java 单例模式:

/**
* 实现单例访问Kerrigan的第四次尝试
*/
public class SingletonKerriganD {     

    /**
    * 单例对象实例
    */
    private static SingletonKerriganD instance = null;     

    public static SingletonKerriganD getInstance() {
        if (instance == null) {
            synchronized (SingletonKerriganD.class) {
                if (instance == null) {
                    instance = new SingletonKerriganD();
                }
            }
        }
        return instance;
    }
}    

我们来看看这个场景:假设线程一执行到instance = new SingletonKerriganD()这句,这里看起来是一句话,但实际上它并不是一个原子操作(原子操作的意思就是这条语句要么就被执行完,要么就没有被执行过,不能出现执行了一半这种情形)。事实上高级语言里面非原子操作有很多,我们只要看看这句话被编译后在JVM执行的对应汇编代码就发现,这句话被编译成8条汇编指令,大致做了3件事情: 

1.给Kerrigan的实例分配内存。 

2.初始化Kerrigan的构造器。

3.将instance对象指向分配的内存空间(注意到这步instance就非null了)。
但是,由于Java编译器允许处理器乱序执行(out-of-order),以及JDK1.5之前JMM(Java Memory Medel)中Cache、寄存器到主内存回写顺序的规定,上面的第二点和第三点的顺序是无法保证的,也就是说,执行顺序可能是1-2-3也可能是1-3-2,如果是后者,并且在3执行完毕、2未执行之前,被切换到线程二上,这时候instance因为已经在线程一内执行过了第三点,instance已经是非空了,所以线程二直接拿走instance,然后使用,然后顺理成章地报错,而且这种难以跟踪难以重现的错误估计调试上一星期都未必能找得出来,真是一茶几的杯具啊。
DCL的写法来实现单例是很多技术书、教科书(包括基于JDK1.4以前版本的书籍)上推荐的写法,实际上是不完全正确的。的确在一些语言(譬如C语言)上DCL是可行的,取决于是否能保证2、3步的顺序。在JDK1.5之后,官方已经注意到这种问题,因此调整了JMM、具体化了volatile关键字,因此如果JDK是1.5或之后的版本,只需要将instance的定义改成“private volatile static SingletonKerriganD instance = null;”就可以保证每次都去instance都从主内存读取,就可以使用DCL的写法来完成单例模式。当然volatile或多或少也会影响到性能,最重要的是我们还要考虑JDK1.42以及之前的版本,所以本文中单例模式写法的改进还在继续。
  • 无锁编程 并发环境下最常用的同步手段是互斥锁和读写锁,例如pthread_mutex和pthread_readwrite_lock,常用的范式为:

      void ConcurrencyOperation() {
          mutex.lock();
          // do something
          mutex.unlock();
      }
    

    这种方法的优点是:

    1、编程模型简单,如果小心控制上锁顺序,一般来说不会有死锁的问题;

    2、可以通过调节锁的粒度来调节性能。

缺点是:

  • 所有基于锁的算法都有死锁的可能;
  • 上锁和解锁时进程要从用户态切换到内核态,并可能伴随有线程的调度、上下文切换等,开销比较重;
  • 对共享数据的读与写之间会有互斥。

无锁编程(严格来讲是非阻塞编程)可以分为lock free和wait-free两种,下面是对它们的简单描述: lock free:锁无关,一个锁无关的程序能够确保它所有线程中至少有一个能够继续往下执行。这意味着有些线程可能会被任意的延迟,然而在每一个步骤中至少有一个线程能够执行下去。因此这个系统作为一个整体总是在前进的,尽管有些线程的进度可能没有其它线程走的快。 wait free:等待无关,一个等待无关的程序可以在有限步之内结束,而不管其它线程的相对执行速度如何。 lock based:基于锁,基于锁的程序无法提供上面的任何保证,任一线程持有了某互斥体并处于等待状态,那么其它想要获取同意互斥体的线程只有等待,所有基于锁的算法无法摆脱死锁的阴影。

lock free 一般是基于CAS(Compare And Swap)操作

CAS(void *ptr, Any oldValue, Any newValue);

即查看内存地址ptr处的值,如果为oldValue则将其改为newValue,并返回true,否则返回false。X86平台上的CAS操作一般是通过CPU的CMPXCHG指令来完成的。CPU在执行此指令时会首先锁住CPU总线,禁止其它核心对内存的访问,然后再查看或修改*ptr的值。简单的说CAS利用了CPU的硬件锁来实现对共享资源的串行使用。

它的优点是:

开销较小:不需要进入内核,不需要切换线程;
没有死锁:总线锁最长持续为一次read+write的时间;
只有写操作需要使用CAS,读操作与串行代码完全相同,可实现读写不互斥。

而在性能层面上,CAS与mutex/readwrite lock各有千秋,简述如下:

单线程下CAS的开销大约为10次加法操作,mutex的上锁+解锁大约为20次加法操作,而readwrite lock的开销则更大一些。 CAS的性能为固定值,而mutex则可以通过改变临界区的大小来调节性能; 如果临界区中真正的修改操作只占一小部分,那么用CAS可以获得更大的并发度。 多核CPU中线程调度成本较高,此时更适合用CAS。

无锁编程还可以通过减少锁范围等方式实现无锁或更轻量级的锁机制,参见java CurrenHhashMap实现:

http://blog.csdn.net/kjfcpua/article/details/11937817

  • 线程中断 java 中提供了interrupt方法中断线程,线程中断实际上是并非剥脱CPU运行时间片而获取的CPU中断,而是提供一个通知机制来告诉线程应该处理中断逻辑。
  • 线程池

java 线程池创建语法:

ExecutorService threadPool = Executors.newFixedThreadPool(3)

java JVM,GC

java NIO,netty

时间: 2024-10-13 10:36:05

java核心技术卷一的相关文章

读《java核心技术卷一》有感

过去一个多月了吧.才囫囵吞枣地把这书过了一遍.话说这书也够长的,一共706页.我从来不是个喜欢记录的人,一直以来看什么书都是看完了就扔一边去,可能有时候有那么一点想记录下来的冲动,但算算时间太紧,很多也是有始无终,毕竟在之前研究研究程序也只是自己的一个爱好而已,但没有想到签了一个程序员的工作.唉,这老天也太捉弄人了吧,让一个学电气工程(强电方向)学生毕业之后去写代码,而且是与硬件完全无关的代码.真是白念几年大学了.行了,就行发这么多牢骚吧. <java核心技术>有两个卷,我只看了卷一,从我的感

Java核心技术 卷一 笔记六 Date类

在Java核心技术卷就行了一前期  date类出现的频率很高  所以就对date类进行了小小的整合 Date类有两个 date类 表示特定时间的类 这个构造函数分配一个Date对象并初始化它代表指定的毫秒数,因为被称为"纪元",即1970年1月1日00:00:00 GMT标准基准时间. 就像格林尼治时间一样  作为一种基准值而存在 一般常用的是date转为string类型 String s=new Date(0).toString(); System.out.println(s.toS

《Java核心技术卷一》笔记 多线程

有时,我们需要在一个程序中同时并行的处理多个任务,如播放器一边要播放音乐同时还要不断更新画面显示,或者是一边执行耗时任务,UI还能一边继续响应各种事件.还有的时候,一个任务需要很长时间才能完成,如果分成多份一起执行,可以极大的缩短需要的时间.多线程可以很好的解决这类问题. 一个程序(进程)如果可以同时执行多个任务,每个并行的任务都是通过一个线程来完成,这就是一个多线程程序.进程拥有自己的一整套数据(变量),各个线程共享进程的数据,线程间通信比进程间通信更简单,线程开销比进程小. Java中为多线

《Java核心技术卷一》笔记 多线程同步(底层实现)

一.锁的基本原理 多个线程同时对共享的同一数据存取 ,在这种竞争条件下如果不进行同步很可能会造成数据的讹误. 例如:有一个共享变量int sum=0, 一个线程正调用 sum+=10,另一个线程正好也在调用sum+=20,期望的结果应该是sum=30. 但是+=操作并不是原子的,虚拟机需要用多条指令才能来完成这个操作(load,add, store),每个指令执行完都有可能被剥夺执行权,同时让另一个线程继续运行.(可以使用javap -c -v CLASS命令将class文件反编译为可阅读的虚拟

java 核心技术卷一笔记 6 .1接口 lambda 表达式 内部类

6.1 接口不是类,是对类的一组需求的描述,这些类需要遵守接口描述的统一格式进行定义.例如:Arrays类中sort方法(可以对对象数组进行排序)前提是对象所属的类必须实现了Comparable 接口. public interface Comparable { int compareTo(Object other) } Comparable public interface Comparable<T> { int compareTo(T other) } Comparable泛型 接口的方法

java 核心技术卷一笔记 6 .2接口 lambda 表达式 内部类

6.2 接口实例 6.2.1 接口与回调 在java.swing包中有一个Timer类,可以使用它在到达给定的时间间隔时发出通告,假如程序中有一个时钟,就可以请求每秒钟获得一个通告,以便更新时钟的表盘. 在构造定时器时,需要设置一个时间间隔,并告知定时器,当到达时间间隔时需要做些什么操作,(java将某个类的对象传递给定时器,然后的定时器调用这个对象的方法.)-----定时器需要知道调用了哪一个方法,并要求传递的对象所属的的类实现了java.awt.event包的ActionListener接口

Java核心技术卷一 4. java接口、lambda、内部类和代理

接口 接口概念 接口不是类,而是对类的一组需求描述,这些类要遵从接口描述的统一格式进行定义. 如果类遵从某个特定接口,那么久履行这项服务. public interface Comparable<T>{ int compareTo(T other); } 任何实现 Comparable 接口的类都需要包含 compareTo 方法,并且这个方法的参数必须是一个 T 对象,返回一个整形数值. 接口的特点: 接口中所有方法自动地属于 public,所以接口的方法不需要提供关键字 public .

Java核心技术卷一 6. java泛型程序设计

泛型程序设计 泛型程序设计:编写的代码可以被很多不同类型的对象所重用. 类型参数:使用<String>,后者可以省略,因为可以从变量的类型推断得出.类型参数让程序更具更好的可读性和安全性. 通配符类型:很抽象,让库的构建者编写出尽可能灵活的方法. 定义简单泛型类 泛型类就是具有一个或多个类型变量的类. //引用类型变量 T ,可以有多个类型变量,public class Pair<T, U>{...} public class Pair<T> { //类定义的类型变量制

Java核心技术卷一 5. java异常、断言和日志

处理错误 由于出现错误而使得某些操作没有完成,程序因该: 返回到一种安全状态,并能够让用户执行一些其他命令 允许用户保存所有操作的结果,并以适当的方式终止程序 需要关注的问题: 用户输入错误 设备错误 物理限制 代码错误 当某个方法不能够采用正常的路径完成它的任务,就可以通过另外一个一个路径退出方法.这种情况下,方法并不返回任何值,而是抛出(throw)一个封装了错误信息的对象.要注意这个方法将会立刻退出,并不返回任何值.调用这个方法的代码也将无法继续执行,异常处理机制开始搜索能够处理这种异常状