此文为本人临时按照线程的几个状态转换的思路整理的笔记(思路见下图),正在不断完善修正,水平有限,难免有疏漏不严谨之处,仅供各位参考学习,也欢迎批评指正和交流学习!
一、如何创建线程
创建线程的方法有很多,即要不就选择继承Thread,要不就实现一个接口
知识点二:区分run方法和start方法
start方法
调用线程的***start方法***是创建了新的线程,这时此线程是处于就绪状态,并没有运行。运行操作的是此Thread类调用方法run()来完成的
run方法
调用线程的***run方法***是在主线程中执行该方法,和调用普通方法一样。run方法是多线程的线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程终止。然后CPU再调度其它线程。
总之,如果未用start方法开启线程,直接运行run()方法 ,只是普通的对象调用方法,该run方法线程体的内容没有在一个新的线程上运行
知识点三:线程的几种状态:
1.新建状态:新创建了一个线程对象
2.就绪状态;在创建线程对象后,调用***start方法***,该线程就处于“可运行线程池”中,等待获得CPU的使用权
以上两种状态代码在上面已贴,此处不贴
3.运行状态:就绪状态的线程得到CPU即进入此状态
4.阻塞状态:线程因为某些原因放弃了CPU的使用权,暂停运行,并等待进入就绪状态
而阻塞又有以下的情况:
等待阻塞:
释放进入等待状态有两种方式:
(1)程序自然离开监视器的范围,即离开synchronized关键字管辖的代码范围
(2)运行的线程执行wait()方法,该线程会释放占用的所有资源,进入等待池
public class MultiThread {
private static class Thread1 implements Runnable{
@Override
public void run() {
synchronized(MultiThread.class){
System.out.println("thread1 创建...");
System.out.println("thread1 就绪中");
try{
//释放锁有两种方式:(1)程序自然离开监视器的范围,即离开synchronized关键字管辖的代码范围
//(2)在synchronized关键字管辖的代码内部调用监视器对象的wait()方法。这里使用wait方法
MultiThread.class.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("thread1 正在运行 ...");
System.out.println("thread1 结束!");
}
}
}
进入锁池状态
等待其他线程调用notify()或notifyAll()方法将它唤醒
被唤醒的线程进入锁池,变为锁池状态,准备争夺锁的拥有权,从而进入就绪状态。假如某个线程没有争夺到锁,它仍旧停留在锁池中等待下一次的争夺
private static class Thread2 implements Runnable{
@Override
public void run() {
//notify方法并不释放锁,即使thread2调用了下面的sleep方法休息10ms,但thread1仍然不会执行
//因为thread2没有释放锁,所以Thread1得不到锁而无法执行
synchronized(MultiThread.class){
System.out.println("thread2 创建...");
System.out.println("thread2 此刻唤醒其他wait线程notify other thread can release wait status ...");
MultiThread.class.notify();
try{
System.out.println("thread2 休息 ");
Thread.sleep(2000);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("thread2 正在运行...");
System.out.println("thread2 结束!");
}
}
}
同步阻塞:
运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入“锁池”中。
其他阻塞
执行***sleep***()或***join***()方法后,线程不会释放它的“锁标志”---->sleep()状态超时、join()等待线程终止或者超时,线程重新转入就绪状态。
//join()方法会使当前线程等待调用join()方法的线程结束后才能继续执行
public class TestJoin {
public static void main(String[] args) {
Thread thread = new Thread(new JoinDemo());
thread.start();
for (int i = 0; i < 20; i++) {
System.out.println("主线程第" + i + "次执行!");
if (i >= 2)
try {
// t1线程合并到主线程中,主线程停止执行过程,转而执行t1线程,直到t1执行完毕后继续。
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
而sleep方法在上面说过了
通过sleep()方法指定等待的时间,让正在执行的线程在指定的时间内暂停执行,进入阻塞状态。但因为它在阻塞时不会释放锁标志,因而锁池里其他线程无法获得锁进入就绪状态
suspend() 和 resume()方法
它们在一起配套使用:suspend()使得一个线程进入阻塞状态,无法自动恢复。只有与它对应的***resume***()才能使线程重新进入可执行状态。
这种特性一般在这种情况下应用:一个线程需要等待另一个线程产生结果。在等的时候,测试发现等待的线程还没产生结果,就让suspend()阻塞对应线程,若结果产生了就调用resume()使其恢复
欢迎大家关注交流!
我的博客地址:GershonHold的博客
我的GitHub地址:GershonHold的Github