Java结构分析与线程并发库

  1.集合继承体系

  用来存储不同类型的对象(基本数据类型除外),存储长度可变。Java集合中实际存放的只是对象的引用,

  每个集合元素都是一个引用变量,实际内容都放在堆内存或者方法区里面,

  但是基本数据类型是在栈内存上分配空间的,栈上的数据随时就会被收回的。

  2.hashMap和HashSet的区别?

  HashMap实现了Map接口,HashMap储存键值对,使用put()方法将元素放入map中,

  HashSet实现了Set接口,HashSet仅仅存储对象,使用add()方法将元素放入set中,

  3.List与Set区别?

  相同点:

  都是接口,用来存储对象

  不同点:

  list是有序可重复的,可以插入null值 常用实现类有ArrayList、LinkedList 和 Vector

  Set是无序不可重复的,只能插入一个null值 常用实现类有 HashSet、LinkedHashSet 以及TreeSet

  4.ArrayList与LinkedList区别?

  相同点:

  他们都是实现的list接口,可以存储多个数据,任意类型

  不同点:

  ArrayList底层基于数组,数组具有索引,所以查询快,添加数据慢,因为他要new一个新数组

  LinkedList底层基于双向链表,由于查询要重头开始,所以查询慢,添加时只需要加一个节点,

  所以添加快

  5.TreeSet与Hashset区别?

  相同点:

  实现的set接口,可以存储多个数据,任意类型

  不同点:

  TreeSet去重主要是定制排序或自然排序

  自然排序 实体类实现了comparable接口

  定制排序 set容器中需要传入一个Comparator接口的实现类

  HashSet去重主要通过hashcode和equals方法一起去重

  6.HashMap Hashtable ConcurrentHashMap Properties区别?

  相同点:

  都是实现的map接口,键值对方式存储值

  不同点:

  HashMap线程不安全,可以以null作为键或值 效率较高

  Hashtable 线程安全 ,不可以以null作为键或值 效率较低

  ConcurrentHashMap ,线程安全,不可以以null作为键或值,效率相对较高

  Properties= Hashtable 。

  7.HashMap put get过程

  put方法调用:

  1.调用hash函数得到key的HashCode值

  2.通过HashCode值与数组长度-1逻辑与运算得到一个index值

  3.遍历索引位置对应的链表,如果Entry对象的hash值与hash函数得到的hash值相等,

  并且该Entry对象的key值与put方法传过来的key值相等则,将该Entry对象的value值赋给一个变量,

  将该Entry对象的value值重新设置为put方法传过来的value值。将旧的value返回。

  4.添加Entry对象到相应的索引位置

  get方法调用

  1.当调用get方法时会调用hash函数,这个hash函数会将key的hashCode值返回,返回的hashCode与Entry数

  组长度-1进行逻辑与运算得到一个index值,用这个index值来确定数据存储在Entry数组当中的位置

  2.通过循环来遍历索引位置对应的链表,初始值为数据存储在Entry数组当中的位置,循环条件为Entry对象不为null,

  改变循环条件为Entry对象的下一个节点

  3.如果hash函数得到的hash值与Entry对象当中key的hash值相等,并且Entry对象当中的key值与get方法传进

  来的key值equals相同则返回该Entry对象的value值,否则返回null

  8.线程的创建方式?

  主要有三种方式:

  1.继承Thread实现的线程类

  需要创建不同Thread对象,自然不共享

  2.通过Runnable接口创建线程类

  该方法需要先 定义一个类实现Runnable接口,并重写该接口的 run() 方法,此run方法是线程执行体。接着创建 Runnable实现类的对象,

  作为创建Thread对象的参数target,此Thread对象才是真正的线程对象。通过实现Runnable接口的线程类,是互相共享资源的。

  3.使用Callable和Future创建线程

  引入 Future接口,此接口可以接受call() 的返回值,RunnableFuture接口是Future接口和Runnable接口的子接口,

  可以作为Thread对象的target 。并且, Future 接口提供了一个实现类:FutureTask 。

  9.线程的状态有哪些 线程中的方法有哪些?

  1.状态:

  新建状态:使用 new 关键字和 Thread 类或其子类建立一个线程对象后

  就绪状态: 当线程对象调用了start()方法之后,该线程就进入就绪状态

  运行状态: 就绪状态获取CPU资源,就可以执行run方法 就是运行状态

  阻塞状态:如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态

  三种阻塞状态:郑州妇科医院 http://www.ytsgfk120.com/

  等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。

  同步阻塞:线程在获取 synchronized 同步锁失败

  其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态或其他

  死亡状态: 一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。

  2.方法:

  yield方法:使当前线程从执行状态变为就绪状态。

  sleep方法:强制当前正在执行的线程休眠,当睡眠时间到期,则返回到可运行状态。不会放弃锁资源

  join方法:通常用于在main()主线程内,等待其它线程完成再结束main()主线程,不会放弃锁资源

  deamon:

  守护线程(deamon)是程序运行时在后台提供服务的线程,并不属于程序中不可或缺的部分。

  当所有非后台线程结束时,程序也就终止,同时会杀死所有后台线程。

  main() 属于非后台线程。

  使用 setDaemon() 方法将一个线程设置为后台线程。

  10.线程安全问题 如何解决

  1.使用synchronized和Lock都可以实现代码的同步

  2.使用数据库的乐观锁机制,即就是在对共享数据进行操作是先查出数据的版本号再去做

  3.使用数据库的悲观锁机制,即利用数据库的行锁或者是表锁来解决线程安全问题

  4.使用队列进行排队处理操作,使用actvicemq、rabbitmq等工具,排队操作

  5.Zookeeper实现分布式锁。简单来说就是利用Zookeeper的节点是否被占用的机制来判断此代码是否可以运行操作

  11.ThreadLocal有什么作用 原理

  作用:

  是解决线程问题的一个很好地思路,通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题

  ThreadLocal比直接使用synchronized同步机制解决线程安全

  原理:

  ThreadLocal提供线程局部变量。这些变量与普通的变量不同之处在于,

  每个访问这种变量的线程(通过它的get或set方法)都有自己的、独立初始化的变量副本。

  12.wait与sleep区别

  相同点:

  它们都可以使线程暂停

  不同点:

  sleep()方法是Thread类的静态方法,是线程用来控制自身流程的,

  他会使此线程暂停执行一段时间,而把执行机会让给其他线程,等到计时时间一到,此线程会自动苏醒

  wait()方法是object类的方法,用于线程间通信,这个方法会使当前拥有该对象锁的进程等待,

  直到其他线程调用notify()方法或者notifyAll()时才醒来,不过开发人员也可以给他指定一个时间,自动醒来。

  wait()方法必须放在同步控制方法和同步代码块中使用

  sleep()方法则可以放在任何地方使用,但是必须捕获异常

  13.synchronize与lock的区别

  共同点:

  都可以使线程安全(锁)

  不同点:

  Lock是一个接口,而synchronized是关键字。

  synchronized会自动释放锁,而Lock必须手动释放锁。

  Lock可以让等待锁的线程响应中断,而synchronized不会,线程会一直等待下去。

  通过Lock可以知道线程有没有拿到锁,而synchronized不能。

  Lock能提高多个线程读操作的效率。

  synchronized能锁住类、方法和代码块,而Lock是块范围内的


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章