【关于线程的一些总结】
关于线程的一些总结
- 线程一般有那些状态
- park和wait的区别是什么
- wait和block的区别在哪里
- 创建线程的方式有哪些
- 创建线程池有哪些方式
线程一般有那些状态
- NEW:线程被创建,但是没有调用start()方法启动,此时,线程还未开始运行;
- RUNNABLE:表示线程JVM里面已经执行了或者已经准备好执行,等待操作系统分配CPU资源执行;
- BLOCKED:表示线程在等待一个监视器锁,例如进入synchronized块时,锁被其他线程持有,那么当前线程则为BLOCKED状态;
- WAITING:表示无期限的等待其他线程执行完成,这个一般是我们手动调用了wait()护着park(),线程就会进入WAITING状态;
- TIME_WAIT:如果wait加park加时间参数(或者sleep()),就会进入TIME_WAIT状态;
- TERMINATED:run()方法执行完或者异常以后就会进入终止状态
park和wait的区别是什么
- 所属机制不同
park:属于Unsafe类提供的底层阻塞机制,是JVM层面的实现;
wait:属于Objece类的同步方法,是Java层面的实现。 - 使用方法不同
// park 的使用方式
LockSupport.park(); // 阻塞当前线程
LockSupport.unpark(thread); // 唤醒指定线程// wait 的使用方式
synchronized (obj) {obj.wait(); // 阻塞当前线程obj.notify(); // 唤醒一个等待线程obj.notifyAll(); // 唤醒所有等待线程
}
- 同步要求不同
park:不需要在同步块调用,可以直接使用
wait:必须在synchronized同步块或方法中调用,否则抛出IllegalMonitorStateException。 - 唤醒机制不同
park:通过unpark(Thread)精确唤醒指定线程,不需要获取特定对象锁;
wait:通过notify()或者notifyAll()唤醒,必须由持有相同对象锁的线程调用。 - 虚假唤醒处理
park:不会出现虚假唤醒,更安全可靠;
wait:可能存在虚假唤醒,通常需要在循环中检查条件。 - 许可机制
park:具有许可证机制,每个线程最多持有一个许可证,调用park时如果由许可证则直接返回并消费许可证,调用unpark时,给线程发放许可证(如果已有则无效)
wait:没有许可证机制,完全依赖对象监视器。 - 应用场景
park:主要用于构建更高级别的同步组件(如ReentrantLock、CountDownLatch等);
wait:用于传统的记忆对象监视器的线程间通信。
wait和block的区别在哪里
- 触发条件不一样,wait是注定触发,调用wait或者park,需要掉哟个notify或者unpark方法唤醒,而Brock是被动触发,当线程尝试获得一个监视器锁的时候,发现锁被其他线程持有,这个时候就会进入Brock状态,直到锁被释放,并且成功获取到锁;
- 使用场景也不一样,wait是协调线程写作的,比如实现生产者-消费者模型,任务的调度等待,而Brock更多是线程资源的竞争导致的一种状态。
创建线程的方式有哪些
主要由Thread类来实现,他提供两个关键的方法:start()和run(),调用start方法会触发地城的native()和start0向操作系统申请资源并等待CPU调度,当线程被CPU调用后会回调Thread的run方法,然后执行run方法:因此启动线程的方式其实hi有Thread的start方法;
我们可以通过以下几种方式来指定执行任务,也就是指定我们的run方法:
- 继承Thread类,重写run方法;
- 实现Runnable接口,重写run方法,并且通过Thread的构造函数传入进去;
- 实现Callable接口,我们可以结合FutureTask和Callable接口来实现异步任务的执行和返回结构的等待。
创建线程池有哪些方式
它的关键实现原理是在线程池里维护阻塞队列,当线程执行完一个任务以后,它并不会立即结束,而是通过自旋的方式从阻塞队列里面去调用tack或者poll方法获取新的任务;如果队列中有任务,就继续执行队列中的任务,如果队列为空,会根据有我们线程池的配置,比如说核心线程数超时时间、能否允许核心线程数回收等来决定是否结束;具体来说就是,如果线程池的线程数大于核心线程或者设置了允许回收且线程在指定的时间内没有获取到新的任务,那么线程就被回收掉;如果线程池的线程数小于或等于核心线程数,那么线程会一直阻塞。