《Java多线程核心技术》总结

#

《Java多线程核心技术》总结

  • synchronized同步方法,同步语句块
  • volatile关键字的主要作用是使变量在多个线程之间可见

  • ThreadLocal

    类ThreadLocal主要解决的就是每个线程绑定自己的值,可以将ThreadLocal类比喻成全局存放数据的盒子,盒子中可以存储每个线程的私有数据。

  • 守护线程

    在java中有两种线程,一种是用户线程,另一种是守护线程。

    守护线程是一种特殊的线程,它的特性有”陪伴”的含义,当进程中不存在非守护线程了,则守护线程自动销毁。典型的守护线程就是垃圾回收线程,当进程中没有非守护线程了,则垃圾回收线程就没有存在的必要了,自动销毁。

  • volatile 关键字

    关键字volatile的主要作用是使变量在多个线程间可见。

  • 线程间通信机制

    • 等待通知机制 wait/notify/interrupt

    • 通过管道进行线程间通信

      PipeInputStream/PipeOutputStream

      PipeReader/PipeWriter

    • join的使用

      在很多情况下,主线程创建并启动子线程,如果子线程中要进行大量的耗时运算,主线程往往将早于子线程结束之前结束。这时主线程想等待子线程执行完成之后再结束,比如子线程处理一个数据,主线程要取得这个数据中的值,就要用到join()方法了。方法join()的作用是等待线程对象销毁。

    • 类ThreadLocal的使用

  • Lock

    • ReentrantLock类

      JDK1.5中新增了ReentrantLock类也能达到类似synchronized关键字来实现线程间的同步互斥,扩展功能上更加强大

      使用示例:

      1
      2
      3
      4
      5
      Lock lock=new ReentrantLock();
      ...
      lock.lock();
      ...
      lock.unlock();
  • 使用Condition实现等待/通知

    类似synchronized与wait()/notify()/notifyAll()方法相结合可以实现等待/通知模式,类ReentrantLock借助于Condition对象也可以实现同样的功能,且具有更好的灵活性

  • Condition对象可以实现多路通知功能

    在一个Lock对象里面可以创建多个Condition(即对象监视器)实例,同一个Lock锁可以创建多个Condition监视器,不同的线程使用不同的Condition监视器进行等待通知,可以有选择性地进行线程通知

  • 公平锁和非公平锁

    锁Lock分为”公平锁”和”非公平锁”,公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO先进先出顺序。而非公平锁就是一种获取锁的抢占机制,是随机获得锁的,和公平锁不一样的就是先来的不一定先得到锁,这个方式可能造成某些线程一直拿不到锁,结果也就是不公平的。(公平与不公平并不是绝对的,公平锁10个线程中可能有1个不按照FIFO规则,但大多数还是按照这个规则)。

  • Lock锁还有许多方法函数:

    getHoldCount()、getQueueLength()、getWaitQueueLength()……

  • ReentrantReadWriteLock类

    类ReentrantLock具有完全互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock()方法后面的任务,虽然线程安全但是效率低下,使用读写锁ReentrantReadWriteLock类,可以提升该方法代码运行速度。

    读写锁表示有两个锁,一个是读操作相关的锁,称为共享锁;一个是写操作相关的锁,称为排他锁。多个读锁之间不互斥,读锁与写锁互斥,写锁与写锁互斥。

    示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ReentrantReadWriteLock lock=new ReentrantReadWriteLock();
    ...
    lock.readLock().lock();
    ...
    lock.readLock().unlock();
    ...
    lock.writeLock().lock();
    ...
    lock.writeLock().unlock();
  • 定时器Timer的使用

    • schedule(TimerTask task,Date time)
    • schedule(TimerTask task,Date firstTime,long period)
    • schedule(TimerTask task, long delay)
    • schedule(TimerTask task, long delay, long period)
    • scheduleAtFixedRate(TimerTask task,Date firstTime,long period)
  • 单例模式与多线程

    懒汉模式中,多线程环境中,”延迟加载”不能实现保持单例的状态,单纯地同步整个代码块会使效率降低或者无法保持单例,使用DCL双检查锁机制。

    示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    volatile static MyObject myObject;
    ...
    public static MyObject getInstance(){
    if(myObject!=null){
    }else{
    //模拟在创建对象之前做一些准备性的工作
    Thread.sleep(3000);
    synchronized(MyObject.class){
    if(myObject==null){
    myObject=new MyObject();
    }
    }
    }
    ...
    }
    ...
    • 还可以使用静态内置类实现单例模式

    • 多线程的序列化和反序列化

      需要添加readResolve()方法:

      1
      2
      3
      4
      5
      ...
      protected Object readResolve(){
      return MyObjectHandler.myObject;
      }
      ...
    • static代码块实现单例模式

      静态代码块中的代码在使用的时候就已经执行了,所以可以应用静态代码块的这个特性来实现单例设计模式。

    • enum枚举数据类型实现单例模式

      枚举enum和静态代码块的特性相似,在使用枚举类时,构造方法会被自动调用,也可以应用其这个特性实现单例设计模式。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      public enum MyObject{
      connectionFactory;
      private Connection connection;
      private MyObject(){
      try{
      ...
      connection=DriverManager.getConnection(url,username,password);
      }catch(...){
      ...
      }
      }
      public Connection getConnection(){
      return connection;
      }
      }
  • 线程的状态

    new、runnable、ready、running、timed waiting、waiting、blocked、terminated

  • 线程组

    可以把线程归属到某一个线程组中,线程组中可以有线程对象,也可以有线程组,组中还可以有线程。这样的组织结构有些类似于树的形式。

  • SimpleDateFormat非线程安全

    • 类SimpleDateFormat是非线程安全的

      • 解决方案1:

        1
        2
        3
        4
        5
        6
        7
        8
        public class DateTools{
        public static Date parse(String formatPattern,String dateString) throws ParseException{
        return new SimpleDateFormat(formatPattern).parse(dateString);
        }
        public static String format(String formatPattern,Date date){
        return new SImpleDateFormat(formatPattern).format(date).toString();
        }
        }

        解决处理错误的原理就是创建了多个SimpleDateFormat类的实例。

      • 解决方案2:

        ThreadLocal类能使线程绑定到指定的对象,使用该类也可以解决多线程环境下SimpleDateFormat类处理错误的情况

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        public class DateTools{
        private static ThreadLocal t1=new ThreadLocal();
        public static SimpleDateFormat getSimpleDateFormat(String datePattern){
        SimpleDateFormat sdf=null;
        sdf=t1.get();
        if(sdf==null){
        sdf=new SimpleDateFormat(datePattern);
        t1.set(sdf);
        }
        return sdf;
        }
        }
  • 线程中出现异常的处理

    • 方法setUncaughtExceptionHandler()的作用时对指定的线程对象设置默认的异常处理器。
    • 方法setDefaultUncaughtExceptionHandler()对所有线程对象设置异常处理器。
-------------本文结束感谢您的阅读-------------