51.创建线程有哪几种方式?
继承Thread类创建线程
定义Thread类的子类,重写run()方法,即线程的执行体创建Thread子类的实例,即创建线程对象调用线程对象的start()方法来启动线程
实现Runnable接口创建线程
定义实现Runnable接口的类,重写run()方法创建Runnable实现类的实例,以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象调用线程对象的start()方法启动线程
使用Callable和Future创建线程
创建Callable接口的实现类,并实现call()方法,该call()方法作为线程执行体,并且有返回值创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。使用FutureTask对象作为Thread对象的target创建并启动新线程。(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
使用线程池,例如用Executor框架
52.说一下 runnable 和 callable 有什么区别?
最大的区别,Runnable的run方法没有返回值,而实现Callable接口的call方法提供返回值用来表示任务运行的结果。
Runnable提供run方法,无法通过throws抛出异常,所有CheckedException必须在run方法内部处理。Callable提供call方法,直接抛出Exception异常。
Runnable可以作为Thread构造器的参数,通过开启新的线程来执行,也可以通过线程池来执行。而Callable只能通过线程池执行。
53.线程有哪些状态?
线程通常都有五种状态,创建、就绪、运行、阻塞和死亡。
创建(NEW):生成线程对象,并没有调用该对象的start方法,这时线程处于创建状态就绪(RUNNABLE):调用线程对象的start方法之后,该线程就进入了就绪状态。如果此时线程调度程序还没有把该线程设置为当前线程,也处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态。运行(RUNNING):线程调度程序将就绪状态的线程设置为当前线程,此时线程进入运行状态,开始运行run中代码阻塞(BLOCKED):线程正在运行的时候被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait方法都可以导致线程阻塞死亡(DEAD):如果run方法执行结束或调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法进入就绪状态。
54.sleep() 和 wait() 有什么区别?
sleep() 方法是线程类(Thread)的静态方法,让调用线程进入睡眠状态,让出执行机会给其他线程,等到休眠时间结束后,线程进入就绪状态和其他线程一起竞争cpu的执行时间。
因为sleep() 是static静态的方法,他不能改变对象的机锁,当一个synchronized块中调用了sleep() 方法,线程虽然进入休眠,但是对象的机锁没有被释放,其他线程依然无法访问这个对象。wait()是Object类的方法,当一个线程执行到wait方法时,它就进入到一个和该对象相关的等待池,同时释放对象的机锁,使得其他线程能够访问,可以通过notify,notifyAll方法来唤醒等待的线程。
55.notify()和 notifyAll()有什么区别?
notify() 方法随机唤醒对象的等待池中的一个线程,进入锁池;notifyAll() 唤醒对象的等待池中的所有线程,进入锁池。
56.线程的 run()和 start()有什么区别?
用start()方法启动线程,不用等待run方法体执行完毕,可以直接执行下面的代码,此时线程处于就绪状态,没有运行,然后调用run()方法完成运行状态,run方法运行结束,线程终止,CPU再调度其他线程。用start()方法真正实现了多线程。
run()方法知识线程里的一个函数,不是多线程的,如果直接调用run(),其实就是调用了一个普通函数。所以在多线程执行时要使用start()方法而不是run()方法。
57.创建线程池有哪几种方式?
线程池:Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的程序都可以使用线程池。
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
58.线程池都有哪些状态?
线程池的5种状态:Running、ShutDown、Stop、Tidying、Terminated。
59.线程池中 submit()和 execute()方法有什么区别?
接收的参数不一样submit有返回值,而execute没有submit方便Exception处理
在 java 程序中怎么保证多线程的运行安全?
线程安全在三个方面体现:
原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作,(atomic,synchronized);可见性:一个线程对主内存的修改可以及时地被其他线程看到,(synchronized,volatile);有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序,(happens-before原则)。