一、什么是进程?
进程是一个正在执行中的程序,每一个进程的执行,都有一个执行的顺序,该顺序就是一个执行路径,或者叫一个工作单元。
二、什么是线程?
线程就是进程中一个独立的控制单元,线程在控制着进程的执行,一个进程中至少有一个线程。
JVM启动时会有一个进程java.exe,该进程中至少有一个线程负责Java程序的执行,而且这个线程运行时代码存在于main方法中,该线程成为主线程。
扩展:其实,JVM启动不止一个线程,还有负责垃圾回收机制的线程。
三、如何在自定义代码中自定义一个线程呢?
答:通过对Api文档的查找,Java已经提供了对线程这类事物的描述,就是Thread类。
步骤:
1、定义类继承Thread。
2、复写Thread类中的run()方法。目的:将自定义的代码存储在run方法中,让线程运行。
3、调用线程的start方法。该方法两个作用:启动线程;调用run方法。
四、为什么要覆盖run()方法?
答:Thread类用于描述线程。该类线程就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run()方法。也就是说,Thread类中的run()方法用于存储线程要运行的代码。
start:开启线程并执行该线程的run()方法,调用底层。
五、如何创建一个线程
创建线程方式一:
继承Thread类
1.子类覆盖父类中的run()方法,将线程运行代码存放在run()方法中。
2.建立子类对象的同时,线程也被创建。
3.通过调用start方法开启线程。
创建线程方式二:实现Runnable接口。
步骤:
1.定义类实现Runnable接口。
2.覆盖Runnable接口中的run()方法(将线程要运行的代码存放在该run()方法中)。
3.通过Thread类建立线程对象。
4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
5.调用Thread类的start()方法开启线程,并调用Runnable接口子类的run()方法。
六、线程的四种状态?
被创建、运行、冻结、阻塞(临时状态)、消亡
临时状态:具备运行资格,但没有执行。
冻结:放弃了执行资格。
sleep()方法:需要指定睡眠时间,单位是毫秒。
一个特殊的状态:就绪,具备了执行资格,但是还没有获取资源。
七、为什么要将Runnable接口的子类对象传递给Thread的构造函数?
答:因为,自定义的run()所属的对象是Runnable接口的子类对象。所以要让线程去执行指定对象的run()方法。就必须明确该run()方法所属对象。
八、实现方式和继承方式有什么区别(重点)?
答:采用实现的方式使得类的扩展能力加强,除了可以继承其他类,还能实现多个接口。线程代码存放在Thread子类的run()方法中。而采用继承的方式,再想继承别的类就不行了。所以说开发中建议使用继承式。线程代码存放在接口的子类run()方法中。
实现方式的好处:避免了单继承的局限性。
多线程的安全问题:当线程多的时候,CPU的切换可能会导致程序出问题。
九、同步的前提?
1.必须要有两个或者两个以上的线程。
2.必须是多个线程使用同一个锁。
3.必须保证同步中只能有一个线程在运行。
好处:解决了多线程的安全问题。
弊端:多个线程需要判断锁,较为消耗资源。
十、多线程出现安全问题怎样分析?
1.明确哪些代码是多线程运行代码。
2.明确共享数据。
3.明确多线程运行代码中哪些语句是操作共享数据的。
十一、为什么同步函数用的是this锁?
答:函数要被对象调用,每个函数都有一个所属对象的引用,那就是this。
十二、如果同步函数被static修饰后,使用的锁是什么呢?
答:通过验证,发现不再是this锁了,因为静态方法中也不可能有this。静态先进入内存,这时还没有对象,所以不应该是this锁,但是一定用该类对应的字节码文件对象。类名.class该对象的类型是class。
结论:静态的同步方法,使用的锁是该方法所在类的字节码文件对象:类名.class。同步代码块使用的锁是this锁。
十三、wait(),notify(),notifyAll()用来操作线程,为什么定义在Object类中?
1.这些方法存在同步中,因为要对监视器(锁)的线程操作,所以要使用在同步中,因为只有同步才有锁的概念。
2.使用这些方法时,必须要标识所属的同步的锁。只有同一个锁上的被等待线程,可以被同一个锁上的notify()唤醒,不可以对不同锁中的线程进行唤醒,也就是说,等待和唤醒必须是同一个锁。
3.锁可以是任意对象,所以任意对象调用的方法一定定义在Object类中。
wait(),sleep()有什么区别?
wait():释放资源,释放锁。
sleep():释放资源,不释放锁。
十四、如何停止线程?
1.定义循环结束标记。因为线程运行代码一般都是循环的,只要控制了循环即可。
2.使用interrupt();中断方法。该方法是结束线程的冻结状态,使线程回到运行状态中来。
注:stop();方法已经过时不再使用。
总结:当没有指定的方式让冻结的线程恢复到运行状态时,这时就需要对冻结状态进行清除。强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。Thread类中提供了该方法:interrupt();。
十五、什么是守护线程?
setDaemon(boolean on);将线程标记为守护线程或用户线程。需要在启动线程前调用,也就是start();前。
特点:后台线程开启后和前台线程共同抢夺CPU执行权运行。当前台线程全部结束,后台线程会自动结束。
十六、join()是什么?
等待该线程终止。
特点:当A线程执行到了B线程的.join()方法时,A就会等待。等B线程执行完,A才会执行,join可以用来临时加入线程执行。
十七、死锁(重点):死锁通常发生在同步中嵌套同步。当一个线程拿到一个同步对象锁时,要进入另一个同步代码块时,而另一个线程拿着这个同步代码块的锁需要进入另一个同步代码块时,这时两个线程互相持着对象锁不放而要进入对方拿着的锁同步代码块时,就会发生死锁。
扩展:
toString():返回该线程的字符串表示形式,包括线程名称、优先级和线程组。
setPriority(int newPriority):更改线程的优先级。默认优先级为5,总共10级,1~10;
MAX_PRIORITY:线程可以具有的最高优先级。
MIN_PRIORITY:线程可以具有的最低优先级。
NORM_PRIORITY:分配给线程的默认优先级。
yield():暂停当前正在执行的线程对象,并执行其他线程。让线程都有机会执行。
|