多线程_基础
一.一个Java程序最少开几个线程?
- 3个:主线程;gc线程;异常处理线程
二.线程的生命周期以及状态?
阻塞的分类:
- 等待阻塞:执行wait(),需要notify()/notifyAll()唤醒
- 同步阻塞:等待拿到锁
- 其他阻塞:执行sleep(),join(),或者发出I/O请求。都会进入阻塞
三.创建线程的几种方式?
创建线程:
- 创建一个Thread对象。new Thread().start;
- 使用线程池 Executors.newFixedThreadPool(10); //创建线程池
定义线程做的事
- 继承Thread类,重写run()
- 需要创建一个子类
- 实现Runnable接口,重写run()
- 打破单继承的局限,可以在实现接口的时候继承自己的父类。
- 可以使用lambda代替 ()->{}
- 实现Callable接口,重写call()
- 有返回值,有异常
- 需要用一个过度类FutureTask,可以使用该类的get()获取返回值
四.sleep,wait,yield,join的区别
sleep(),wait()的区别?
- 所属的类不同:sleep来自Thread类,wait来自Object类
- 有没有释放锁(释放资源)
- sleep:不释放 wait:释放,进入等待池中(主要就是为了线程的通讯)
- sleep:不释放 wait:释放,进入等待池中(主要就是为了线程的通讯)
- 使用的范围不同
- sleep:任何地方 wait:必须使用在同步代码块/同步方法中
- sleep:任何地方 wait:必须使用在同步代码块/同步方法中
- 是否有异常
- sleep:有,需要捕获 wait:没有
- sleep:有,需要捕获 wait:没有
补充:解释上面出现的名词
- 锁池:需要竞争同步锁的线程都先放在锁池中,锁一旦释放,锁池中的线程开始抢锁
- 等待池:当线程执行wait(),就会进入等待池中。执行notify()/notifyAll()就会将等待池中的线程放到锁池中(也就是唤醒)
yield和join
- yield():线程让步
- 暂停当前正在执行的线程对象,并执行其它线程。不进入阻塞
- 当前线程交出cpu权限,让cpu执行其他线程(但是CPU可能重新分配时,再次执行该线程)
- join():线程插入
- 在线程a中调用线程b的join(),此时线程a进入阻塞状态,直到线程b完全执行完以后,线程a才结束阻塞状态。
五.其他一些小问题
怎么理解线程安全问题?
- 多个线程操作共享数据时,就会产生线程安全问题
- 造成这个问题的本质就是堆空间是线程共享的
并发,并行,串行的区别?
- 串行:执行完一个程序再执行下一个程序
- 并行:多个事情,在一个时间点内发生。经常是对于多核cpu
- 并发:多个事情,在一个时间段内发生。在这个时间段中cpu快速切换,感觉像一起执行
- 并发编程的本质:充分利用CUP的资源
守护线程?
java中两种线程:守护线程(后台线程) 非守护线程(用户线程)
- 守护线程是专门给所有的用户线程(非守护线程)提供服务的线程,不是专门给一个线程提供服务
- gc垃圾回收线程就是典型的守护线程,当JVM中没有任何的用户线程执行,守护线程就会自动的断开
- 使用守护线程中产生的线程也是守护线程
- 不要把I/O,file操作交给守护线程,因为它随时可能中断(没有用户线程执行的时候)
- 对于线程池Executors,就算你把它设置为守护线程,也会变为非守护线程
- 使用thread.setDaemon(true);//将线程设置为守护线程
线程终止的几种方式?
- 正常运行结束
- 使用退出标志退出线程(将run()的所有内容放在while(flag)中)
- Interrupt()方法结束线程 while (!isInterrupted()){..Thread.sleep().} 推荐
- Interrupt():如果线程处于阻塞状态,终止阻塞。抛出异常。然后在异常处理中break;
- stop()方法结束线程 不推荐
- 强制终止线程,释放该线程的所有的锁。这样做就会导致锁释放,造成线程不安全。
线程是否越多越好? 不一定,线程多了上下文切换就多了
- 对于计算的程序,线程数等于cpu核数最好
- 对于i/o程序,线程数等于i/o任务数最好
寄语:把努力当成你的一种习惯,而不是一时热血