1、进程和线程的区别是什么?
进程是执行着的应用程序,而线程是进程内部的一个执行序列,一个进程可以有多个线程。线程又叫做轻量级的进程
2、创建线程有几种不同的方式?
有三种方式可以创建线程
继承Thread类
实现Runnable接口
应用程序可以使用Executor框架来创建线程池
一般来说,实现RUnnable接口的这种方式更加的受欢迎,因为不需要继承Thread类,在应用设计中已经继承了别的对象的情况下,这需要多继承才能实现,而在java中是不支持多继承的,但是却可以多实现,同时线程池是非常高效的,很容易死实现和使用
3、概括的解释一下线程的几种可用状态
(1) 新建new :表示新创建了一个线程对象
(2) 可运行(runnable):线程对象创建之后,其他线程调用了该对象(比如main线程)的start()方法、该状态的线程位于可以运行的线程池中,等在带被线程调度选中,获取CPU的使用权
(3) 运行*(running) 可运行状态的线程获取了CPU的时间片(timeslice),执行程序代码
(4) 阻塞(block)阻塞状态是指线程因为某种原因放弃了CPU的使用权,也就是让出了CPUtimeslice,暂时停止运行。知道线程进入可运行状态,才有机会再次获取CPU timeslice,然后再次转到running状态,其中阻塞分为三种情况:
4.1 等待阻塞:运行running的线程执行o.wait()方法,jvm会把该线程放入等待队列(waitting queue)中
4.2同步阻塞;运行(running)的线程在获取对象的同步锁的时,若该同步锁,被别的县城占用 ,则jvm会把该线程放入锁池中
4.3 其他阻塞:运行running的线程执行Thread.sleep(long ms)或者是t.join()方法或者是发出了io请求时,jvm会把该线程置为阻塞状态。当sleep()状态超时的时候,join()等待线程终止或者是超时或者时候i/o处理完毕是,此案城重新转入可运行(runnable)状态
(5) 死亡:线程run()、main() 方法执行结束,或者因为异常退出了run()方法,则该线程结束生命周期。死亡的线程不可以再次复生
4、同步方法和同步代码块的区别是什么?
同步方法默认用this或者是当前类class对象作为锁
同步代码块可以选择使用什么来加锁,比同步方法更加的细颗粒度,我们可以选着只同步会发生同步问题的部分代码而不是整个方法
5、什么是死锁*(deadlock)?
指的是两个或者两个以上的线程都在等待对方执行完毕才能继续往下执行的时候就发生了死锁。结果就是这些线程都陷入了无限的等待中
6、如何确保n个线程可以访问n个资源同时又不至于导致死锁呢?
这个其实就是使用多线程,一种非常简单的避免死锁的方式就是:指定获取锁的顺序,并强制线程按照指定的顺序获取锁,因此如果所有的线程都是以同样的顺序加锁和释放锁,就不会出现死锁了
7、sleep()和wait()的区别?
sleep指的是线程被调用的时候,占着CPU不工作,形象地说就是占着CPU睡觉,此时系统的CPU部分资源被占用,其他线程无法进入,会增加时间限制
wait表示线程处于进入等待状态,形象的说明为等待使用CPU,此时线程不占用任何资源,不增加事件 限制
8、实现同步的方式
同步是线程中的重要概念。同步的使用可以保证在多线程运行的环境中,程序不会产生设计之外的错误结果,同步的实现方式有两种:同步方法和同步块,这两种方式都要使用到synchronized关键字
8 .1同步方法
既有synchronized关键字修饰的方法
由于java的每一个对象都有一个内置锁,当用此关键字修饰方法的时候,内置锁就会保护整个方法,在调用该方法前,需要获取到内置锁,否则就是出于阻塞状态。
代码:public synchronized void save(){}
注意:synchronized关键字也是可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类
8.2同步代码块
既有synchronized关键字修饰的语句块
被该关键字修饰的语句快会自动被加上内置锁,从而实现同步
代码:synchronized (object){
}
注意:同步是一种高开销的操作,因此应该尽量减少同步的内容、
通常没有必要同步整个方法,使用synchd代码块同步关键代码就可以