线程池是如何关闭非核心线程的

在 Java 中,多线程的核心实现类是 ThreadPoolExecutor,该类提供了多线程的几个参数,用于开发人员自定义自己的线程池。

线程池的参数

1
2
3
4
5
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime,
TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
//...
}

线程池一共有 7 个参数,其中跟本次相关的有三个,分别是 corePoolSize、maximumPoolSize、keepAliveTime,这三个参数代表的意思如下:

  • corePoolSize:当线程池中的任务数小于 corePoolSize 或者线程池中的任务数大于 corePoolSize 但是小于阻塞队列的最大长度,那么线程池中的核心线程数就睡 <= corePoolSize
  • maximumPoolSize:当线程池中的任务数已经达到队列上限并且线程池中的线程数 < maximumPoolSize,此时线程池就会将线程数增加至 maximumPoolSize
  • keepAliveTime:代表线程的空闲时间,也就是线程等待多久以后可以被销毁
阅读更多

Thread.sleep(0)-vs-Thread.yield()

简介

Thread.sleep(long)yield() 都表示的是让出当前线程的 CPU 时间片,两者在执行的时候,都不会去释放自己已经持有的锁。

多线程

在现代的处理器中,以 4核心CPU 为例,这表示在同一个时刻,只会有 4 个线程在并行执行,而在每一个核心内部,多个线程其实是顺序执行的,它们的执行顺序依赖于线程的调度算法。

线程调度算法

阅读更多

ThreadLocalMap 简单分析

ThreadLocal

在使用多线程的时候,如果需要保存一份线程自己私有的一部分变量,避免其他线程污染这个变量的话,一般都会自己手动 new 一个 ThreadLocal,如下代码:

1
2
ThreadLocal<String> threadLocal = new ThreadLocal<>();
threadLocal.set("test");

当需要在某一刻使用这个变量的时候,只需要手动调用下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
threadLocal.get();
```

## ThreadLocalMap
ThreadLocalMap 是 ThreadLocal 的一个静态内部类,每一个线程在创建的时候都会有这个 ThreadLocalMap 变量,它的作用就是存储每一个通过 `threadLocal.set()` 方法存入的值,本质上也是一个HashMap。

先看下它的一个内部类:
### Entry
不同于 WeakHashMap 是继承自 HashMap 的Entry,ThreadLocalMap 的Entry 则是自己的一个内部类。
```java
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
阅读更多

线程的interrupt和stop区别,以及线程的中断机制

interrupt

在Java里面线程的中断是一个协作式的,也就是说线程会在自己合适的时候自己中断自己,一般来讲线程如果需要中断的话有如下两种方法:

  • 捕获InterruptException
  • 通过Thread的interrupted()或者isInterrupted()方法,但是需要注意的是interrupted会清除这个线程的状态

当一个线程调用另一个线程的interrupt的时候,另一个线程并不会马上结束,而是会设置一个中断的状态,如果一个线程处于阻塞的状态,那么此时该线程会马上抛出一个InterruptException,由上层的代码进行处理。
若线程没有处于阻塞的话,此时线程还是会执行的。但是线程需要自己在合适的地方通过上述的两个方法来判断自己是否应该中断。如果自己

stop

阅读更多

关于Java线程的一些思考

消费者和生产者的模型:

今天在看《现代操作系统》P73页的一个关于多线程的竞态条件的时候书中说到了唤醒等待位方法,这个方法使我突然想起联想到以前在Java多线程中sleep()方法会清除中断状态的一些类似之处:
树上的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#definde N 100
int count =0;
void producer(void){
int item;
while(True){
item=producer_item();
if (count == N) sleep();
insert_item(item);
count=count+1;
if (count == 1 )wakeup(consumer);
}
}

void consumer(void){
int item;
while(true){
if (count == 0)sleep();
item =remove_item();
count=count -1;
if (count == N-1) wakeup(producer);
consumer_item()
}
}

在书中提到过一个情况就是:当消费者判断count==0的时候是会睡眠的,但是此时由于某种情况(线程的sleep()方法还没被执行完),而恰巧生产者又生产了一个item,导致此时count加一为1,而当count为1的时候生产者是会发出一个wakeup信号给消费者的,此时,由于消费者并没有睡眠因此会忽略掉该信号,而当消费者真正睡眠之后又由于生产者再不会进行通知,导致队列被生产者塞满,从而该模型阻塞。
那么为了解决该方法,书中引入了唤醒等待位方法,该方法就是在生产者发出信号给消费者的时候添加一个中断状态,而当该线程需要进行睡眠的时候会先判断状态,若是wakeup则不进行睡眠

Java多线程中的引用:

阅读更多