9.创建线程有哪几种方式?
- 继承Thread类,通过重写run方法来定义线程的执行逻辑
class MyThread extends Thread {@Overridepublic void run() {System.out.println("线程执行的代码");}
}
public class Main {public static void main(String[] args) {MyThread thread = new MyThread();thread.start();}
}
- 实现Runnable接口来定义线程任务,将该任务传递给Thread类的构造函数来创建线程;
优点:这种方式更符合面向对象的设计原则,将任务和执行任务的线程分开,可以多个线程共享一个Runnable对象,更方便的对共享资源进行操作。
class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("通过实现Runnable接口创建的线程执行的代码");}
}
public class Main {public static void main(String[] args) {MyRunnable runnable = new MyRunnable();Thread thread = new Thread(runnable);thread.start();}
}
- 实现Callable接口
- 使用Executors工具类创建线程池;优点:线程池可以控制并发线程的数量,防止因为创建过多线程导致资源耗尽,还可以对线程进行同意的管理和调度。
10.线程的run()和start()有什么区别?
run()方法时线程的执行体,包含了线程执行的代码逻辑,但run方法时空方法,需要进行重写;
start()方法是用于启动一个新线程的方法,当调用start时,jvm会创建一个新线程,并在这个新线程中调用run方法来执行线程任务;
11.线程的生命周期和七种状态
- 新建状态(new):当使用new创建了一个线程对象后,线程就处于新建状态;此状态下线程仅仅是一个对象,尚未开始执行,没有分配cpu资源,也没有执行run方法的代码。
- 就绪状态(Runnable):当线程对象调用start方法后,线程就进入就绪状态;此状态下,线程已经准备好运行,等待cpu时间片的分配。
- 运行状态(Running):当就绪状态的线程获得CPU时间片后,就会进入运行状态,执行run方法的代码;运行状态的线程会独占cpu资源,直到时间片完成或者其他原因而暂停执行。
- 阻塞状态(Blocked):当线程因为某些原因而无法继续执行暂停运行时,就会进入阻塞状态,比如等待获取锁;这状态的线程不会占用cpu资源。
- 等待状态(Waiting):线程进入等待状态是因为调用了一些特定的方法,比如wait方法,jojn方法等,需要其他线程进行相应唤醒操作;
- 超时等待状态(Timed Waiting):跟等待状态类似,但线程会等待一段时间后被自动唤醒;
- 终止状态(Terminated):当线程的run方法执行完毕或者线程因为异常而退出时,线程就进入终止状态;此状态线程已经结束了它的生命周期,不会再被调度执行,占用的资源也会被系统回收。
12.sleep()和wait()有什么区别?
- 所属类:sleep时Thread类的静态方法,可以直接通过Thread类调用,而不用通过线程对象调用;wait是Object类的方法,意味着任何对象都可以调用。但是必须在同步块或者同步方法中调用。
- 对线程的影响:sleep被调用后,线程进入超时等待状态,在睡眠时间内,线程不会占用cpu资源,但仍持有对象的锁;调用wait方法后,线程进入等待状态,会释放对象的锁
- 唤醒方式:sleep方法会在线程睡眠时间结束后自动唤醒,重新进入就绪状态,等待cpu资源的分配;调用wait方法的线程,线程必须通过其他线程调用同一个对象的notify或者notifyall方法来唤醒。
- 适用场景:sleep()方法主要是让线程暂停一段时间,实现简单的延时功能;wait()方法通常用于线程间的通信和协作,当一个线程需要等待某个条件满足时使用。
13. 如何停止一个正在运行的线程?
- 使用标志位:在共享变量中设置一个标志位,线程执行过程中定期检查这个标志位,需要停止线程时,将标志位设置停止状态。
- 使用interrupt()方法:这个方法时Thread类提供的一个方法,用于中断线程,但是不能直接停止线程的执行,而是发送一个中断信号,需要一些其他机制配合使用。比如会出现阻塞的方法调用中会抛出异常来中断,对于没有阻塞的线程,需要在代码中手动检查isInterrupted()标志来决定是否中断线程。
- stop方法:会直接停止线程的执行,可能导致共享资源没有被正确释放。
14.synchronized 的作用?
synchronized 关键字是用来控制线程同步的,在多线程环境下,控制synchronized 的代码段不会被多个线程同时执行。
- 互斥性(保证原子操作):用于实现线程之间的互斥访问
- 可见性:在多线程的环境下,由于每个线程都有自己的工作内存,共享变量在多个线程的工作内存中的副本可能不一致,它在释放锁之前,还会对共享变量修改并立即刷新到主内存中,获取锁的线程会从主内存中重新读取共享变量的最新值。
- 可重入性:它是可重入锁,意味着一个线程获取了一个对象的锁,可以再次获取同一个对象的锁而不会导致死锁。