面试 -- 多线程( 一) -- 基础
1.什么是线程?什么是多线程?线程和进程的区别是什么?
答:
(1)线程是进程的一个实体,是CPU调度和分派的基本单位,是比进程更小的能够独立运行的基本单位,同一进程中的多个线程之间可以并发执行,能够和同属于一个进程的其他线程共享进程所拥有的所有资源。
(2)多线程是指一个资源被多个线程同时调用而造成的多个线程同时执行的情况。实际上多线程是一个线程执行了一会之后其他线程又执行一会,并不是同时执行。使用多线程可以把长时间占用系统资源的任务放到后台处理,提高了系统的运行速度。
(3)线程和进程的区别:
①进程是操作系统资源分配的基本单位,线程是任务调度和执行的基本单位;
②线程是进程的子集,是比进程更小的执行单位,一个进程中可以有很多线程,每个线程并行执行不同的任务。不同的进程使用不同的内存空间,所有线程共享同一块内存空间和资源。各线程协同工作,负担比进程小得多。
③进程是程序的一次执行过程,是系统运行的基本单位。系统运行一个程序是进程从创建、运行到消亡的过程。一个进程就是一个执行程序。进程会占用某些资源,如内存空间、CPU时间片、文件等。
另外:进程间的通信方式:管道、信号、消息队列、共享内存、信号量、套接字
2.守护线程和用户线程的区别。
答:Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程)
用户线程即运行在前台的线程,而守护线程是运行在后台的线程。守护线程的作用是为其他前台线程的运行提供便利服务,并且在普通、非守护线程仍然运行时才需要,比如垃圾回收线程就是一个守护线程。
用户线程和守护线程唯一不同之处就在于虚拟机的离开:如果 User Thread(用户线程)已经全部退出运行了,只剩下Daemon Thread(守护线程)存在了,虚拟机也就退出了。 因为没有了被守护者,Daemon也就没有工作可做了,也就没有继续运行程序的必要了。
守护线程并非只有虚拟机内部提供,用户在编写程序时也可以自己设置守护线程。用户可以用Thread的setDaemon(true)方法设置当前线程为守护线程。
3.创建线程的几种方式?
答:
(1)通过继承Thread类,重写run()方法来实现;
(2)实现Runnable接口,并实现该接口的run()方法;
(3)实现Callable接口,重写call方法;
实现Runnable接口可能更优。原因:a、Java不支持多继承,继承了Thread类意味着不能继承其他类;而实现Runnable接口还能继承其他类;b、类可能只要求可执行即可,因此继承Thread类的开销过大;
4.什么是死锁?产生死锁的条件有哪些?
答:死锁是指两个或以上的进程在执行过程中,因争夺资源而造成一种相互等待的现象,若无外力作用,它们将无法推进下去,如果系统资源充足,进程的资源请求都能得到满足,死锁出现的可能性就很低,否则会因争夺有限的资源而陷入死锁。
产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
只要上述条件之一不满足,就不会发生死锁。避免死锁的算法 -- 银行家算法
5.为什么wait、notify和notifyAll这些方法不在Thread类里面?
答:Java提供的锁是对象级别的,而不是线程级别的,每个对象都有锁,通过线程获得。如果线程需要等待某些锁,那么调用对象的wait()就有意义了。如果wait()方法定义在Thread类中,线程等待哪个对象的锁就不确定了。由于wait()、notify()和notifyAll()都是锁级别的操作,所以把它们定义在Object类中就是因为锁属于对象。
6.Java多线程中调用wait() 和 sleep()方法有什么不同?
答:wait()方法用于线程间的通信,如果等待条件为真且其他线程被唤醒时它会释放锁,而sleep()方法仅仅释放CPU资源或者让当前线程停止一段时间,但不会释放锁。
7.有三个线程T1,T2,T3,怎么确保它们按顺序执行?
答:在多线程中有多种方法让线程按特定顺序执行,你可以用线程类的join()方法在一个线程中启动另一个线程,另外一个线程完成该线程继续执行。为了确保三个线程的顺序你应该先启动最后一个(T3调用T2,T2调用T1),这样T1就会先完成而T3最后完成。
8.线程有几种状态,他们是怎么转化的?
答:线程的生命周期大体分为5种状态:新建、就绪、执行、阻塞、死亡。
新建: 通过new关键字创建Thread类的对象;
就绪: 对象调用start()方法;
运行:处于就绪状态的线程一旦得到CPU,就进入运行状态并自动调用自己的run()方法;
阻塞:处于运行状态的线程,执行sleep()方法,或等待I/O设备资源,让出CPU并暂时中止自己运行,进入阻塞状态
阻塞 --> 就绪:睡眠时间已到,或等待的I/O设备空闲下来,线程便进入就绪状态,重新到就绪队列中等待CPU。当再次获得CPU时,便从原来中止位置开始继续运行。
死亡:(正常情况下)线程任务完成,或者主线程的main()方法完成时,线程就被认为死亡。死去的线程不能复生。
9.多线程上下文切换是什么?
答:多线程上下文切换就是指CPU控制权由一个已经正在运行的线程切换到另外一个就绪并等待获取CPU执行权的线程的过程。
----------有时间再继续写----------