本节只做一个链接,已经有博主整理好了。
参考链接:《剑指Java面试-Offer直通车》–Java多线程与并发
Java多线程与并发
一、进程和线程的区别
进程和线程的由来
进程和线程的区别
1、进程是资源分配的最小单位,线程是CPU调度的最小单位
2、线程不能看做独立应用,而进程可看做独立应用
3、进程有独立的地址空间,互不影响;线程只是一个进程中的不同执行路径
4、线程有自己的堆栈和局部变量,但线程没有独立的地址空间,多进程的程序比多线程程序健壮
5、进程的切换比线程的切换开销大
Java进程和线程的关系
1、Java对操作系统提供的功能进行封装,包括进程和线程
2、运行一个Java程序会产生一个Java进程,而每个Java进程包含至少一个线程
3、每个进程对应一个JVM实例,每个JVM实例唯一对应一个堆,多个线程共享JVM里面的堆,每一个线程都有自己私有的栈
4、Java采用单线程编程模型,程序会自动创建主线程
注:耗时的操作放入子线程中进行,以避免阻塞主线程
5、主线程可以创建子线程,原则上要后于子线程完成执行
注:通常主线程是最后完成执行,因为它需要执行各种关闭动作
二、线程的start和run方法的区别
注:
1、run()方法只是Thread的一个(重写)普通方法的调用(还是在主线程里执行)
2、调用start()方法会创建一个新的子线程并启动
3、子线程启动后会去执行run方法
三、Thread和Runnable的关系
注:
1、Thread是一个类,Runnable是一个接口,Thread类实现了Runnable接口
2、真实run方法是在Runnable接口中
3、Runnable接口没有start方法,那么Runnable接口的实现类会先创建线程,把Runnable子类的实例传进去
4、因为Java类的单一继承原则,为了提升系统可扩展性,推荐通过使业务类实现Runnable接口将业务逻辑封装在run方法里。
5、暂时掌握两种创建方式,继承Thread类、实现Runnable接口(无返回值)、实现Callable接口(有返回值)
Java创建线程的四种方式
注:Runnable接口中的run()方法的返回值是void,它做的事情只是纯粹地去执行run()方法中的代码而已;Callable接口中的call()方法是有返回值的,是一个泛型,和Future、FutureTask配合可以用来获取异步执行的结果。
四、如何实现处理线程的返回值
注:
和线程相关的业务逻辑需要放入到run()方法里面,但是run方法是没有参数的,并且也没有返回值的
如何给run()方法传参
如何实现处理线程的返回值
获取子线程返回值的方式主要有三种:
1、主线程循环等待法
2、使用Thread类的join()阻塞当前线程以等待子线程处理完毕
3、通过Callable接口实现,通过FutureTask或者线程池获取。
注:只有子线程执行完FutureTask的get方法才可以执行
五、线程的状态
Thread源码枚举类型State中,包括六种状态:
1、新建未启动New、
2、运行中Runnable、
3、无限等待Waiting、
4、限期等待Timed Waiting、
5、阻塞 Blocked(等待获取排它锁)、
示例:当某个线程进入synchronized关键字修饰的方法或者代码块的时候,即获取锁执行的时候,其它想进入此方法或者代码块的线程就只能等着,它们的状态便是Blocked。
6、已终止(结束)Terminated
注:线程一旦终止了,就不能再复生
sleep和wait的区别
基本的差别:
sleep()方法是Thread类的方法,wait()方法是Object类中定义的方法。
sleep()方法可以在任何地方使用。wait()方法只能在synchronized方法或者synchronized块中使用(已经获取锁才能释放锁)。
最本质的差别:是否让出CPU或同时CPU+锁
Thread.sleep()方法只会让出CPU,不会导致锁行为的变化。(如果当前线程是拥有锁的,那么Thread.sleep()方法不会让线程释放锁,而只会主动让出CPU。让出CPU之后,CPU就可以去执行其它任务了)
Object.wait