Java多线程知识点

来源:互联网 发布:flac player for mac 编辑:程序博客网 时间:2024/06/16 00:23
1. Java创建线程之后,直接调用start()方法和run()的区别
start()用来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法,这里run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。
若直接调用run(),它只是类的一个普通方法而已,程序中依然只有主线程这一个线程,就跟执行一个普通方法一样。
run()方法必须是public访问权限,返回值类型为void.。

2. 常用的线程池模式以及不同线程池的使用场景
Java通过Executors提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。


3. newFixedThreadPool此种线程池如果线程数达到最大值后会怎么办,底层原理。

代码展示:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
实现原理:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
使用固定大小的线程池并使用无限大的队列


4. 多线程之间通信的同步问题,synchronized锁的是对象,衍伸出和synchronized相关很多的具体问题,例如同一个类不同方法都有synchronized锁,一个对象是否可以同时访问。或者一个类的static构造方法加上synchronized之后的锁的影响。

一个类不同方法都有synchronized锁,是互斥的,synchronized可以修饰static方法,但是这是锁的对象时整个类。
详解:http://www.2cto.com/kf/201209/152881.html

5. 了解可重入锁的含义,以及ReentrantLock 和synchronized的区别
什么是sychronized
sychronized是java中最基本同步互斥的手段,可以修饰代码块,方法,类.
在修饰代码块的时候需要一个reference对象作为锁的对象.
在修饰方法的时候默认是当前对象作为锁的对象.
在修饰类时候默认是当前类的Class对象作为锁的对象.

synchronized会在进入同步块的前后分别形成monitorenter和monitorexit字节码指令.在执行monitorenter指令时会尝试获取对象的锁,如果此没对象没有被锁,或者此对象已经被当前线程锁住,那么锁的计数器加一,每当monitorexit被锁的对象的计数器减一.直到为0就释放该对象的锁.由此synchronized是可重入的,不会出现自己把自己锁死.

什么是ReentrantLock
以对象的方式来操作对象锁.相对于sychronized需要在finally中去释放锁 
除了synchronized的功能,多了三个高级功能.
等待可中断,公平锁,绑定多个Condition.
1.等待可中断
在持有锁的线程长时间不释放锁的时候,等待的线程可以选择放弃等待.   tryLock(long timeout, TimeUnit unit)
2.公平锁
按照申请锁的顺序来一次获得锁称为公平锁.synchronized的是非公平锁,ReentrantLock可以通过构造函数实现公平锁.    new RenentrantLock(boolean fair)
3.绑定多个Condition
通过多次newCondition可以获得多个Condition对象,可以简单的实现比较复杂的线程同步的功能.通过await(),signal();


6. 同步的数据结构,例如concurrentHashMap的源码理解以及内部实现原理,为什么他是同步的且效率高

详解:http://blog.csdn.net/liuzhengkang/article/details/2916620,表、桶、节点

7. atomicinteger和Volatile等线程安全操作的关键字的理解和使用
volatile不具备原子性,主要讲volatile和synchronized的差别。
在Java中,为了保证多线程读写数据时保证数据的一致性,可以采用两种方式:
同步
如用synchronized关键字,或者使用锁对象.
volatile
使用volatile关键字
用一句话概括volatile,它能够使变量在值发生改变时能尽快地让其他线程知道.
volatile详解
首先我们要先意识到有这样的现象,编译器为了加快程序运行的速度,对一些变量的写操作会先在寄存器或者是CPU缓存上进行,最后才写入内存.
而在这个过程,变量的新值对其他线程是不可见的.而volatile的作用就是使它修饰的变量的读写操作都必须在内存中进行!
volatile与synchronized
volatile本质是在告诉jvm当前变量在寄存器中的值是不确定的,需要从主存中读取,synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住.
volatile仅能使用在变量级别,synchronized则可以使用在变量,方法.
volatile仅能实现变量的修改可见性,但不具备原子特性,而synchronized则可以保证变量的修改可见性和原子性.
volatile不会造成线程的阻塞,而synchronized可能会造成线程的阻塞.
volatile标记的变量不会被编译器优化,而synchronized标记的变量可以被编译器优化.

8. 线程间通信,wait和notify

调用yield和sleep并没有释放锁,而调用wait则释放锁。可以通过notify()/notifyAll(),或者时间到期,从wait()中恢复执行。
wait() 挂起该线程,线程等待.notify() 随机唤醒一个线程 notifyAll() 唤醒所有线程.

9. 定时线程的使用
主要涉及到两个类,一个是java.util.Timer,一个是java.util.TimerTask。Timer:是一种工具,用Timer操作线程,可以在后台执行线程中的任务,可以控制这个任务执行一次,或者定期重复执行。TimerTask就是Timer需要安排的任务。

10. 场景:在一个主线程中,要求有大量(很多很多)子线程执行完之后,主线程才执行完成。多种方式,考虑效率。

详解:http://www.jb51.net/article/96842.htm
方法一:设置一个集合,将所有的线程放到list集合中,判断集合是否还有元素,
方法二:设置计数器进行- - 操作;方法三:使用java.util.concurrent.CountDownLatch代替MyCountDown,用await()方法代替while(true){...}

11. 进程和线程的区别

线程是指进程内的一个执行单元,也是进程内的可调度实体.与进程的区别:
(1)地址空间:进程内的一个执行单元;进程至少有一个线程;它们共享进程的地址空间;而进程有自己独立的地址空间;
(2)资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
(3)线程是处理器调度的基本单位,但进程不是.
4)二者均可并发执行.

12. 什么叫线程安全?举例说明

如果你的代码所在的进程中有多个线程同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他变量的值也和预期一样,我们就说是线程安全。线程安全问题都是由全局变量和静态变量引起的

13. 线程的几种状态
新建,就绪,运行,阻塞,死亡;
新建:当使用new操作创建一个线程
就绪:调用了start(),线程分配cpu以外的全部资源,等待获得cpu调度
运行:线程获得cpu,开始真正执行run()方法
阻塞:正在运行的线程没有运行结束,暂时让出CPU,这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。有以下的几种原因:
1、线程调用sleep()方法
2、线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者;
3、线程试图得到一个锁,而该锁正被其他线程持有;
4、线程在等待某个触发条件;
死亡:正常退出或者一个异常结束stop()、interrupt或者设置标志位

14. 并发、同步的接口或方法

详解:http://blog.csdn.net/woshisap/article/details/43119569

15. HashMap 是否线程安全,为何不安全。 ConcurrentHashMap,线程安全,为何安全。底层实现是怎么样的。

不是线程安全地。当多个线程同时操作同一个数组位置的时候,也都会先取得现在状态下该位置存储的头结点,然后各自去进行计算操作,之后再把结果写会到该数组位置去,其实写回的时候可能其他的线程已经就把这个位置给修改过了,就会覆盖其他线程的修改。
   详解:http://www.jb51.net/article/96842.htm

16. J.U.C下的常见类的使用。 ThreadPool的深入考察; BlockingQueue的使用。(take,poll的区别,put,offer的区别);原子类的实现。
17. 简单介绍下多线程的情况,从建立一个线程开始。然后怎么控制同步过程,多线程常用的方法和结构
详解:http://developer.51cto.com/art/201509/490965.htm
18. volatile的理解
volatile关键字为域变量的访问提供了一种免锁机制
b.使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新
c.因此每次使用该域就要重新计算,而不是使用寄存器中的值
d.volatile不会提供任何原子操作,它也不能用来修饰final类型的变量

19. 实现多线程有几种方式,多线程同步怎么做,说说几个线程里常用的方法

常用的有两种方式:实现Runnable接口和继承Thread类。
多线程同步有以下的几种方式,使用synchronized、特殊域变量volatile、重入锁ReentrantLock()、使用局部变量
start(); 表示该线程处于活动的,可以抢时间片的状态,而不是开始运行。
interrupt(); 表示将线程对象中断。如果该线程正处于sleep状态,会抛出异常(最好不用,不如让run方法完成执行)
stop(); 表示将线程直接终止。(已过时,不安全,如果有正在打开的资源无法关闭,而线程直接被关闭)。
sleep(); 表示该语句写在那个线程中表示要将当前线程睡眠。
只能在同步控制方法或同步块中调用wait()、notify()和notifyAll()
原创粉丝点击