1.线程和进程的联系和区别是什么?
- 进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,它是系统进行资源分配和调度的一个独立单位。
- 线程是进程的一个实体,是CPU调度和分配的基本单位。线程基本不拥有系统资源,与同一个进程的其他线程共享进程中所拥有的所有资源。
联系:
- 一个进程可以包括多个线程。
2.什么是前台线程,什么是后台线程?
- 应用程序必须运行完所有的前台线程才可以退出;
- 后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。
3.创建线程有几种方法?它们之间的区别是什么?
第一种方式:直接继承Thread类创建对象
- Thread子类无法再从其它类继承(java语言单继承)。
- 编写简单,run()方法的当前对象就是线程对象,可直接操作。
第二种方式:直接继承Thread类创建对象
- Thread子类无法再从其它类继承(java语言单继承)。
- 编写简单,run()方法的当前对象就是线程对象,可直接操作。
4.线程的生命周期有哪些状态?哪些方法可以改变这些状态?
- 创建状态:线程对象已经创建,还没有在其上调用start()方法。
- 可运行状态:当线程有资格运行,但调度程序还没有把它选定为运行线程时线程所处的状态。当start()方法调用时,线程首先进入可运行状态。在线程运行之后或者从阻塞、等待或睡眠状态回来后,也返回到可运行状态。
- 运行状态:线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。这也是线程进入运行状态的唯一一种方式。
- 阻塞状态:这是线程有资格运行时它所处的状态。如执行了join/sleep/wait方法,会让出CPU,只有当引起阻塞的原因消除时,线程才能转入就绪状态。
- 死亡状态:当线程的run()方法完成时就认为它死去。或者抛出一个未捕获到的Exception或Error。
5. 什么是线程安全?为什么会产生线程安全问题?如何解决线程安全问题?
解释:
线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。
原因:
是由于不同线程获取到资源时进行运算,但未来得及写入时,线程改变,则另外线程读入的资源就是错误,导致所有线程写入读入不同步。
解决办法:
使用监视器,使用关键字synchronized监视同步代码块,当一个线程获得监视权限时,别的线程就无法获得,保证每时每刻只有一个线程调用某一方法,保证原子性。
6.什么是线程的同步通信?同步通信又是如何实现的?
线程同步通信:线程同步通信是希望实现两个或多个线程之间的某种制约关系
实现:两个线程之间得同步通讯,需要方法前的synchronized,变量前的volatile,方法中的wait和notify,还有布尔型变量指示器,他们之间的种种配合才能实现线程的同步通讯。
7.什么是死锁?
所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进,指两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。
下面我们通过一些实例来说明死锁现象。
先看生活中的一个实例,两个人面对面过独木桥,甲和乙都已经在桥上走了一段距离,即占用了桥的资源,甲如果想通过独木桥的话,乙必须退出桥面让出桥的资源,让甲通过,但是乙不服,为什么让我先退出去,我还想先过去呢,于是就僵持不下,导致谁也过不了桥,这就是死锁。
在计算机系统中也存在类似的情况。例如,某计算机系统中只有一台打印机和一台输入 设备,进程P1正占用输入设备,同时又提出使用打印机的请求,但此时打印机正被进程P2 所占用,而P2在未释放打印机之前,又提出请求使用正被P1占用着的输入设备。这样两个进程相互无休止地等待下去,均无法继续执行,此时两个进程陷入死锁状态。
8.如何让某个对象的A方法内的一个代码块和另一个方法B实现同步?
课本例9.11
9.设计一个程序产生两个线程A与B,B线程执行10秒钟后,被A线程中止。
class Account
{
int b=0;
void change(int _a) {b=_a;}
int getb() {return b;}
volatile private int value;
synchronized void put(int i)
{
value = value + i;
System.out.println("存入"+i+", 账上金额为:"+value);
}
}
class Save implements Runnable
{
//int a=2000;
private Account a1;
public Save(Account a1)
{
this.a1 = a1;
}
public void run()
{
while(a1.getb()==0) {
try {
Thread.sleep(900);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
a1.put(1);
}
System.out.println("10秒已到,停止存钱。stop!");
}
}
class Fetch implements Runnable
{
//int a=20;
private Account a1;
public Fetch(Account a1)
{this.a1 = a1 ;}
public void run()
{
if(a1.getb()==0) {
try {
Thread.sleep(9000);
} catch (InterruptedException e) {}
}
a1.change(1);
}
}
public class Test{
public static void main(String[] args){
Account a1 = new Account();
new Thread(new Save(a1)).start();
new Thread(new Fetch(a1)).start();
}
}
转自学校17级学长
该代码较为容易,设置sleep()函数,等函数结束后,线程开始执行将另外一个线程停止