问题整理 - 多线程
1、实现线程有哪几种方式
继承Thread类
实现Runnable接口,重写run()方法
实现Callable接口,重写call()方法 ,返回Future对象结果
线程池:ExecutorService 中submit(runnable/callable)返回一个Future,Future可用来获得任务的执行结果或者取消任务
2、用Runnable还是Thread?
Java不支持类的多重继承,但允许你调用多个接口,如果类要继承其他类,当然是用Runnable接口
3、Thread 类中的start(:和 run(:方法有什么区别?
start()方法被用来启动新创建的线程,而且start()内部调用了run()方法
当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程
4、线程池有什么作用
提前创建好指定数量的线程放在池中,等需要使用的时候就从池中使用,减少临时创建线程从而提高效率
同时频繁的创建和销毁线程会浪费大量的系统资源,增加并发编程的风险
5、线程池的参数
线程池的核心线程数
线程池程最大线程数量
线程活动保持时间:非核心线程闲置时的超时时长,超过这个时长,非核心线程就会被回收
用于指定线程活动保持时间参数的时间单位(分 秒)
任务队列:用于保存等待执行的任务的阻塞队列
6、Executors线程池有哪几种, 各有什么区别
newSingleThreadExecutor 创建一个单线程化的线程池,单线程串行执行所有任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
7、ExecutorService 的submit()与execute()区别
submit()参数可以Runnable 也可以是Callable 有Future返回值 ,可以通过Future.get()进行抛出异常的捕获
execute()参数只有Runnable 没有返回值
8、Runnable()与Callable()区别 (都通过start()启动线程)
Callable接口方法是call(),Runnable接口方法是run();
Callable的call方法可以通过Future.get()进行抛出异常 (Callable可以返回装载有计算结果的Future对象 ,Callable的 call()方法可以返回值和抛出异常)
Runnable的run方法中的异常只能在本类中处理,无法上抛
9、wait、sleep、yield的区别
wait会释放锁,其他线程竞争获得锁,用于线程间交互,可以通过notify/notifyall唤醒线程
sleep一直持有锁,线程处于阻塞状态
yield会释放线程所占有的CPU资源 会临时暂停当前正在执行的线程 ,来让有同样优先级的正在等待的线程有机会执行(谦让)。线程CPU资源的获取取决于调度器
10、notify 和 notifyAll有什么区别?
notify() 只随机唤醒一个 wait 线程
notifyall() 唤醒所有 wait 线程 (移动到锁池中,等待锁竞争) 并允许他们争夺锁确保了至少有一个线程能继续运行
11、为什么wait, notify 和 notifyAll这些方法不在thread类里面?
JAVA提供的锁是对象级的而不是线程级的,每个对象都有锁,通过线程获得。
如果wait()方法定义在Thread类中,线程正在等待的是哪个锁就不明显了
12、为什么wait和notify方法要在同步块中调用?
如果不在synchronized块中会抛出monitor异常,
wait/notify是线程之间的通信,他们存在竞态,必须保证在满足条件的情况下才进行wait
如果不加锁的话,那么wait被调用的时候可能wait的条件已经不满足了,由于错误的条件下进行了wait,那么就有可能永远不会被notify到,所以需要强制wait/notify在synchronized中
13、如何在两个线程间共享数据
1 通过共享对象来实现这个目的 (obj里面定义的变量 ObjClass obj = new ObjClass(); new Thread(obj).start();) 多个线程共享一个变量
2 使用像阻塞队列这样并发的数据结构 (synchronized 等 互斥)
14、线程间如何通信
一.syncrhoized加锁的线程的Object类的wait()/notify()/notifyAll()
二.ReentrantLock类加锁的线程的Condition的await()/signal()/signalAll() (Condition condition = lock.newCondition())
三.BlockingQueue阻塞队列 控制线程通信(共享对象丢到队列里)
四.CountDownLatch 多个线程启动,也可以等待多个线程执行完后呼唤线程 (创建线程池共享变量) 等等
15、Java中如何停止一个线程?
调用interrupt方法是在当前线程中打了一个停止标志,当遇到阻塞(sleep/wait) 会抛出异常
interrupt()与return结合使用也能实现停止线程 if(this.isInterrupted()) return;
16、interrupt()、interrupted、isInterrupted区别 (线程关闭)
interrupt()的作用是中断本线程("中断"状态,不会停止线程),当阻塞的地方(wait/sleep),会识别中断标记,并抛出InterruptedException后,清除中断标记(false)
interrupted()判断线程是否被中断,并且清除中断状态
isInterrupted()判断线程是否被中断
interrupt()与return结合使用也能实现停止线程 if(this.isInterrupted()) return;
17、有三个线程T1,T2,T3,怎么确保它们按顺序执行?
一.可以把3个线程放到newSingleThreadExecutor(单例阻塞队列线程池)
二.t1.statrt t2执行t1.join() t3执行t2.join()
18、什么是线程安全?Vector是一个线程安全类吗?
多线程和单线程每次运行结果和单线程运行的结果是一样的,就是线程安全的
Vector 不是线程安全的,只能保证单个操作安全,复合操作同样不安全 (复合操作不具有原子性,中间被插入打断了)
例 1: T1.getvector , T2.getvector
2: T2.remove(1)
3: T1.get(1) -- 抛出错误
19、什么是FutureTask?
可用于异步获取执行结果或取消执行任务的场景
只有当运算完成的时候结果才能取回,如果运算尚未完成get方法将会阻塞.
。。。。待完善。。。。