东莞市凤岗建设局网站,app页面制作,东莞微网站制作公司,网站建设更改架构师面试必问的多线程状态切换及常用方法一、问题背景Java架构师面试中#xff0c;多线程状态切换及常用方法几乎是必问的#xff0c;要掌握创建多线程的方式和方法。二、创建多线程的几种方式2.1方式一继承Threadpublic class ThreadDemo extends Thread{public void run(…架构师面试必问的多线程状态切换及常用方法一、问题背景Java架构师面试中多线程状态切换及常用方法几乎是必问的要掌握创建多线程的方式和方法。二、创建多线程的几种方式2.1方式一继承Threadpublic class ThreadDemo extends Thread{public void run(){}}直接继承Thread可以创建线程2.2方式二实现Runnable接口通过实现Runnable接口实现创建public class Thread1 implements Runnable{public void run(){}}new Thread(new Thread1()).start();2.3方式三Callable接口的实现Callable接口实现了多线程带有返回值线程运行可以返回结果值class ThreadDemo implements Callable { Override public Integer call() throws Exception { int num 0; for (int i 0; i 1000; i) { num i; } return num; }}带有返回值ThreadDemo td new ThreadDemo(); //1.执行 Callable 方式需要 FutureTask 实现类的支持用于接收运算结果。 FutureTask result new FutureTask(td); new Thread(result).start(); //2.接收线程运算后的结果 try { Integer sum result.get(); //FutureTask 可用于 闭锁 类似于CountDownLatch的作用在所有的线程没有执行完成之后这里是不会执行的 System.out.println(sum); System.out.println(------------------------------------); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); }线程result.get就是返回的结果值三、多线程的生命周期运行状态转换Java线程具有五种基本状态新建状态(New)当线程对象对创建后即进入了新建状态如Thread t new CallThread();就绪状态(Runnable)当调用线程对象的start()方法(t.start();)线程即进入就绪状态。处于就绪状态的线程只是说明此线程已经做好了准备随时等待CPU调度执行并不是说执行了t.start()此线程立即就会执行运行状态(Running)当CPU开始调度处于就绪状态的线程时此时线程才得以真正执行即进入到运行状态。注就 绪状态是进入到运行状态的唯一入口也就是说线程要想进入运行状态执行首先必须处于就绪状态中阻塞状态(Blocked)处于运行状态中的线程由于某种原因暂时放弃对CPU的使用权停止执行此时进入阻塞状态直到其进入到就绪状态才 有机会再次被CPU调用以进入到运行状态。根3.1几种阻塞状态据阻塞产生的原因不同阻塞状态又可以分为三种1.等待阻塞运行状态中的线程执行wait()方法使本线程进入到等待阻塞状态2.同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用)它会进入同步阻塞状态3.其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时线程重新转入就绪状态。3.2结束生命周期死亡状态(Dead)线程执行完了或者因异常退出了run()方法该线程结束生命周期。3.3就绪、运行与死亡状态之间的切换当多线程获得了处理器CPU资源就从就绪状态跃迁为运行状态当多线程调用yield方法多线程就从运行状态变为就绪状态当一个线程执行完了或遇到Exception就变为死亡状态四、如何中止线程使用Java原子变量volatile表示一次只有一个线程能使用此状态。如下当volatile变量改变时可以终止线程public class MainThread extends Thread { //volatile修饰符用来保证其它线程读取的总是该变量的最新的值 public volatile boolean exit false; Override public void run() { ServerSocket mainSocket new ServerSocket(1090); while(!exit){ mainSocket.accept(); //阻塞等待 ... } }使用stop可以终止线程但是会造成线程不安全。stop会立刻停止run方法中的数据包括catch和finally中的语句块会造成异常导致文件数据库得不到关闭。使用interupt中断线程是线程安全的不会立即结束线程只是通知线程提前告知:try { InterruptFGThread1 t new InterruptFGThread1(); t.start(); Thread.sleep(1000); t.interrupt(); } catch (InterruptedException e) { e.printStackTrace(); }public void run() { super.run(); for(int i 0; i 5000; i) { System.out.println(i i); } }设置了中断状态但中断不会起作用此时得用到isInterrupted方法来终止线程public void run() { f(); for(int i 0; i 5000; i) { //判断是否被中断 if(Thread.currentThread().isInterrupted()){ //处理中断逻辑 break; } System.out.println(i i); }当线程感知到interrupt中断时会通过isInterrupted()进行终止程序控制操作可以控制。Interrupt与Stop相比线程安全程序可控并不实际终止线程。五、sleep与wait方法的区别sleep来自Thread类和wait来自Object类。sleep不出让系统资源wait是进入线程等待池等待出让系统资源其他线程可以占用CPU。一般wait不会加时间限制因为如果wait线程的运行资源不够再出来也没用要等待其他线程调用notify/notifyAll唤醒等待池中的所有线程才会进入就绪队列等待OS分配系统资源。5.1wait方法只限于同步锁状态中wait用于Object对象发出wait后。可以通过notify和notifyAll来唤醒线程。但是只能用于synchronized同步块中synchronized(obj){ obj.notify() //或者obj.wait() }5.2异常sleep方法必须捕获异常try{sleep(500);}catch(Exception e){log.error();}wait方法无需捕获异常作用于Object使用wait后采用notify与notifyAll唤醒从而变为运行状态多线程常见于面试中一定要注意。