习题
1.线程和进程的联系和区别是什么?
线程指的是进程中的一个执行场景,也就是执行流程
每一个进程都是一个应用程序,都有独立的内存空间
同一个进程中的线程共享其进程中的内存和资源(共享的内存是堆内存和方法区内存,栈内存不共享,每个线程都有自己的栈内存。)
一个进程对应一个应用程序,例如在Windows操作系统中打开QQ,在Java开发环境下启动jvm,就表示启动了一个线程。在同一个操作系统中,可以同时启动多个线程。
2.什么是前台线程,什么是后台线程?
main()函数即主函数,是一个前台线程,前台进程是程序中必须执行完成的,而后台线程则是java中所有前台结束后结束,不管有没有完成,后台线程主要用与内存分配等方面。
3.创建线程有几种方法?他们之间的区别是什么?
两种。
第一种:继承Thread类
首先定义一个类继承Thread类,再复写Thread类中的run方法。
再创建线程的子类对象,调用线程的start方法。
第二种:实现Runnable接口
首先定义类实现Runnable接口,覆盖Runnable接口中的run方法,将线程要运行的代码存放在该run方法中。通过Thread类建立线程的对象。将Runnable接口的子类对象作为实际参数传递给Thread的构造函数。
区别
实现方式和继承方式的区别
1,继承方式的代码比较简单.( 在没有父类时,使用继承方式.)
实现方式好处:避免了单继承的局限性.
在定义线程时,建议使用实现方式.
2,存放代码位置不一样
继承Thread:线程代码存放Thread子类的run方法中.
实现Runnable,线程代码存在接口的子类的run方法中.
4.线程的生命周期有哪些状态?哪些方法可以改变这些状态?
新建状态
(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();
就绪状态
(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
运行状态
(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就 绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
阻塞状态
(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。
根据阻塞产生的原因不同,阻塞状态又可以分为三种:
1.
等待阻塞
:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
2.
同步阻塞
– 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;
3.
其他阻塞
– 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
死亡状态
(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
5.什么是线程安全?为什么会产生线程安全问题?如何解决线程安全问题?
线程安全
:指多个线程在执行同一段代码的时候采用加锁机制,使每次的执行结果和单线程执行的结果都是一样的,不存在执行程序时出现意外结果。
产生原因
:在单线程中不会出现线程安全问题,而在多线程编程中,有可能会出现同时访问同一个资源的情况,这种资源可以是各种类型的的资源:一个变量、一个对象、一个文件、一个数据库表等,而当多个线程同时访问同一个资源的时候,就会存在一个问题:由于每个线程执行的过程是不可控的,所以很可能导致最终的结果与实际上的愿望相违背或者直接导致程序出错。
解决办法
:在Java中,可以使用synchronized关键字来标记一个方法或者代码块,当某个线程调用该对象的synchronized方法或者访问synchronized代码块时,这个线程便获得了该对象的锁,其他线程暂时无法访问这个方法,只有等待这个方法执行完毕或者代码块执行完毕,这个线程才会释放该对象的锁,其他线程才能执行这个方法或者代码块。
6.什么是线程的同步通信?同步通信又是怎样实现的?
当使用多个线程来访问同一个数据时,非常容易出现线程安全问题(比如多个线程都在操作同一数据导致数据不一致),所以我们用同步机制来解决这些问题。
实现同步机制有两个方法:
1.同步代码块:
synchronized(同一个数据){} 同一个数据:就是N条线程同时访问一个数据。
2同步方法:
public synchronized 数据返回类型 方法名(){}
就是使用 synchronized 来修饰某个方法,则该方法称为同步方法。对于同步方法而言,无需显示指定同步监视器,同步方法的同步监视器是 this 也就是该对象的本身(这里指的对象本身有点含糊,其实就是调用该同步方法的对象)通过使用同步方法,可非常方便的将某类变成线程安全的类。
7.什么是死锁?
线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行。当线程进入对象的synchronized代码块时,便占有了资源,直到它退出该代码块或者调用wait方法,才释放资源,在此期间,其他线程将不能进入该代码块。当线程互相持有对方所需要的资源时,会互相等待对方释放资源,如果线程都不主动释放所占有的资源,将产生死锁。
8.如何让某个对象的A方法内的一个代码块和另一个方法B实现同步?
把A方法内的代码块 单独定义一个方法出来叫做C方法,C方法执行完 调用B方法 就同步了
9.设计一个程序产生两个线程A与B,B线程执行了10秒钟后,被A线程中止。
package birthday;
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();
}
}