zoukankan      html  css  js  c++  java
  • 核心类库阶段回顾

    1.数组(Array) 和列表(ArrayList) 有什么区别?
      Array可以包含基本类型和对象类型,ArrayList只能包含对象类型

      Array大小固定,ArrayList的大小是动态变化的。

      ArrayList提供了更多的方法和特性:比如 :addAll(),removeAll(),iterator()等等。

      对于基本数据类型,集合使用自动装箱来减少编码工作量。但是,当处理固定大小基本数据类型的时候,这种方式相对较慢。

    2.ArrayList 和 Vector 的区别
       这两个类都实现了List接口(List接口继承了Collection接口),他们都是有序集合,即存储在这两个集合中的元素的位置都是有顺序的,相当于一种动态的数组,我们以后可以按位置索引号取出某个元素,并且其中的数据是允许重复的——这是由List集合规范制订的。

      而且ArrayList与Vector底层都是基于数组的,因此它们的实现代码也大致相似。区别在于Vector是一个古老的集合,从JDK1.0开始就有了,因此它包含了大量方法名很长的方法,JDK 1.2开始引入集合框架,引入List接口,才让Vector实现了List接口,因此又增加了一些List接口中定义的方法。总体来说,ArrayList可以完全代替Vector,除了在一些很古老的API中强制要求使用Vector之外。

      Vector还有一个特征:它是线程安全的,因此性能比较差。而ArrayList并不是线程安全的,因此性能较好。实际上即使我们要在多线程环境下使用List集合,也应该选择ArrayList,而不是Vector,因为Java还提供了一个Collections工具类,它可以把ArrayList包装成线程安全的集合类,例如如下代码:

    1 List list = Collections.synchronizedList(new ArrayList());
    3.HashMap,TreeMap,HashTable 的区别?
       Map接口有三个比较重要的实现类,分别是HashMap、TreeMap和HashTable。

      TreeMap是有序的,HashMap和HashTable是无序的。

      Hashtable的方法是同步的,HashMap的方法不是同步的。这是两者最主要的区别。

      这就意味着Hashtable是线程安全的,HashMap不是线程安全的。HashMap效率较高,Hashtable效率较低。 如果对同步性或与遗留代码的兼容性没有任何要求,建议使用HashMap。 查看Hashtable的源代码就可以发现,除构造函数外,Hashtable的所有 public 方法声明中都有 synchronized关键字,而HashMap的源码中则没有。

      Hashtable不允许null值,HashMap允许null值(key和value都允许)

      父类不同:Hashtable的父类是Dictionary,HashMap的父类是AbstractMap

      Hashtable中hash数组默认大小是11,增加的方式是 old*2+1。

      HashMap中hash数组的默认大小是16,而且一定是2的指数。

    4.HashMap 的工作原理是什么?
       Java中的HashMap是以键值对(key-value)的形式存储元素的。HashMap需要一个hash函数,它使用hashCode()和equals()方法来向集合/从集合添加和检索元素。当调用put()方法的时候,HashMap会计算key的hash值,然后把键值对存储在集合中合适的索引上。如果key已经存在了,value会被更新成新值。HashMap的一些重要的特性是它的容量(capacity),负载因子(load factor)和扩容极限(threshold resizing)。
    5.什么是序列化,如何实现序列化?
      序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。
      序列化是为了解决在对对象流进行读写操作时所引发的问题。序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。
    6.进程和线程有什么区别?
      根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位
      在开销方面:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。

      所处环境:在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)

      内存分配方面:系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源。

      包含关系:没有线程的进程可以看做是单线程的,如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。

    7.java 当中如何实现线程呢?
      在Java中线程的调度是抢占式调度,线程的实现常用的有两种方法
      1.继承Thread
      MyThread.java
    1 public class MyThread extends Thread{
    2     public void run(){
    3         //run方法就是线程要执行任务的方法
    4         //这是执行路径 触发方式不是调run而是用start()启动系统
    5         for(int i=0;i<10;i++){
    6             System.out.printIn("m线程"+i);
    7         }
    8     }
    9 }

      Demo.java

     1 public class Demo{
     2     //多线程技术 抢占
     3     public static void main(String[] args){
     4         MyThread m=new MyThread();
     5         //启动m线程
     6         m.start();
     7         for(int i=0;i<10;i++){
     8             System.out.printIn("main'线程");
     9         }
    10     }
    11 }

    程序启动 > main线程开启 > main方法执行 > 创建m对象 >
      1.m线程开启 循环十次
      2.main本身循环十次

      2.实现Runnable

      用于给线程执行任务

      MyRunnable.java

    1 public class MyRunnable implements Runnable{
    2     //线程的任务
    3     public void run(){
    4         for(int i=0;i<10;i++){
    5             System.out.prinIn("m线程");
    6         }
    7     }
    8 }

      Demo.java

     1 public class Demo{
     2     public static void main(String[] args){
     3         //1.实现Runnable 创建一个任务对象
     4         MyRunnable r=new MyRunnable();
     5         //2.创建一个线程并分配任务
     6         Thread t=new Thread(r);
     7         //3.执行这个线程
     8         t.start();
     9         for(int i=0;i<10;i++){
    10             System.out.printIn("主线程");
    11         }
    12     }
    13 }

    执行顺序和上同

    实现Runnable和继承Thread相比优势

    1. 通过创建任务给线程分配的方式,适合多线程同时执行情况。
    2. 避免单继承局限。
    3. 任务与线程分离提高程序健壮性。
    4. 线程池技术仅授权Runnable型任务,不接收Thread型。
    8.说说线程的生命周期
    • New(初始化状态)
    • Runnable(可运行/运行状态)
    • Blocked(阻塞状态)
    • Waiting(无时间限制的等待状态)
    • Timed_Waiting(有时间限制的等待状态)
    • Terminated(终止状态)
    9.多线程并发或线程安全问题如何解决?
      1:通过volatile 关键字修饰变量,可以实现线程之间的可见性,避免变量脏读的出现,底层是通过限制jvm指令的重排序来实现的适用于一个线程修改,多个线程读的场景
      2:通过synchronized锁(任意对象)来实现线程同步,自动锁的思想,底层实现原理:当有线程进入同步代码块之后,利用jvm的计数器将锁的标记置为1,当别的线程再想进入的时候,发现锁的标记为1,该线程就去锁池等待,当第一个线程出来之后,锁的标记会置为0,之后cpu会随机分配一个线程再次进入同步代码块.
      3:通过lock锁的机制,进行手动lock,和unlock,但是这种很容易出现死锁。注意加锁以及解锁的顺序,就可以避免死锁
      4:通过线程安全的集合类,可以解决并发问题4
        ConcurrentHashMap
        CopyonWriteArrayList
      5:使用并发包下面的原子类,底层使用的是cas机制(乐观锁),可以解决并发问题 atomicInteger 线程安全的原子整型类
      6:使用线程池来创建和管理线程,也可以一定程度上解决并发问题
      7:使用ThreadLocal来修饰变量,可以解决并发问题
      ThreadLocal底层是怎么实现的?
      多个线程会复制一份threadLocao变量的副本进行操作,互不影响,来保证线程安全的
    10.synchronized 和 ReentrantLock 的区别
       功能区别:
        这两种方式最大区别就是对于Synchronized来说,它是java语言的关键字,是原生语法层面的互斥,需要jvm实现。而ReentrantLock它是JDK 1.5之后提供的API层面的互斥锁,需要lock()和unlock()方法配合try/finally语句块来完成
     
        便利性:很明显Synchronized的使用比较方便简洁,并且由编译器去保证锁的加锁和释放,而ReenTrantLock需要手工声明来加锁和释放锁,为了避免忘记手工释放锁造成死锁,所以最好在finally中声明释放锁。
     
        锁的细粒度和灵活度:很明显ReenTrantLock优于Synchronized
      性能的区别:
        在Synchronized优化以前,synchronized的性能是比ReenTrantLock差很多的,但是自从Synchronized引入了偏向锁,轻量级锁(自旋锁)后,两者的性能就差不多了,在两种方法都可用的情况下,官方甚至建议使用synchronized,其实synchronized的优化我感觉就借鉴了ReenTrantLock中的CAS技术。都是试图在用户态就把加锁问题解决,避免进入内核态的线程阻塞。

    实现Runnable

  • 相关阅读:
    同一位置(同一个ImageView)显示不同的图片levellist (转)
    LinearLayout android:layout_weight的理解
    给C盘减减肥,让你电脑飞一般速度!
    (Android实战)界面设计注意事项
    利用sender的Parent获取GridView中的当前行(转载)
    用SQL查看字符串ASCII码
    自己写DataPage分页
    连接长宽高的UDF
    把Dictionary绑定到combox
    trackbar和processbar功能合并
  • 原文地址:https://www.cnblogs.com/zhangzhongkun/p/14483464.html
Copyright © 2011-2022 走看看