大家好,又见面了,我是你们的朋友全栈君。
一、什么是进程,什么是线程?
进程是一个程序运行的实例,一个进程拥有自己独立的地址空间,一般来说,一个进程是无法访问另一个进程的资源的,可以通过管道、套接字来实现;
线程是操作系统运行调度的最小单元,它被包含在进程里面,是进程中实际的运行单位;
二、线程池的好处?
1.通过new Thread来创建线程池会比较耗时,性能差,当我们在使用线程的时候,有可能会出现(创建线程+销毁线程)的时长>线程执行(业务逻辑)的时长;
2.线程缺乏统一管理,可能会出现无限制的创建线程,线程之间相互竞争,争夺资源而导致系统崩溃;
3.缺乏更多的管理功能,比如定时执行、定期执行、线程中断;
相比较于new Thread,创建线程的好处在于:
1.重用已存在的线程,避免线程新建和消亡产生的开销。
2.可以控制最大并发数,避免同时多个线程执行,争夺资源,导致系统崩溃;
3.拥有更多的功能,比如:定时执行,定期执行,控制并发数,单线程等功能;
三、java提供了哪些线程池?
java是通过ExecuterService来提供线程池的,他提供了四种线程池的实现;
1.newCacheThreadPool:一种可缓存的线程池,若线程池长度超出处理需要,可灵活回收空闲线程,当没有空闲线程可回收时,则创建新线程,线程池长度无限制;
ExecutorService executorService = Executors.newCachedThreadPool();
2.newFixedThreadPool:一种定长的线程池,通过控制线程最大并发数,超过了线程的最大并发数,则在队列中等待其他线程的释放;
ExecutorService executorService = Executors.newFixedThreadPool(3);
for(int i=0; i<10; i++){
final int thred = i;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":"+thred);
}
});
}
3.newScheduleThreadPool:一种定长的线程池,可支持定时以及周期性的执行线程;
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
//以当前时间开始,每三秒间隔周期性的执行任务
executorService.schedule(new Runnable() {
@Override
public void run() {
System.out.println("3 s");
}
}, 3, TimeUnit.SECONDS);
//一秒后开始执行,此后每三秒执行任务
executorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd hh:mm:ss"));
}
}, 1, 3, TimeUnit.SECONDS);
4.newSingleThreadPool:一个单线程化的线程池,只会通过唯一的工作线程执行任务,保证所有线程都按照指定任务执行;
ExecutorService executorService = Executors.newSingleThreadExecutor();
四、spring提供了哪些线程池?
spring提供的七种类型的线程池,其中我们主要使用的是ThreadPoolTaskExecutor,配置方式如下:
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!-- 线程池维护线程的最少数量 -->
<property name="corePoolSize" value="5" />
<!-- 允许的空闲时间 -->
<property name="keepAliveSeconds" value="200" />
<!-- 线程池维护线程的最大数量 -->
<property name="maxPoolSize" value="10" />
<!-- 缓存队列 -->
<property name="queueCapacity" value="20" />
<!-- 对拒绝task的处理策略 -->
<property name="rejectedExecutionHandler">
<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
</property>
</bean>
主要包括以下几个参数:
corePoolSize:线程池最少维护的数量
keepAliveSeconds:允许的空闲时间
maxPoolSize:线程池维护现场的最大数量
queueCapacity:缓存队列
rejectedExecutionHandler:对拒绝task的处理策略
execute(Runable)方法执行过程
1.当线程池里的线程数量小于corePoolSize时,即使当前线程池里面的线程都出于空闲状态,也会新建线程来处理任务;
2.当线程池里的线程数量等于corePoolSize时,若缓存队列里面的数据未满则任务放入缓存队列里面等待
3.当线程池里的线程数量大于corePoolSize小于maxPoolSize时,若缓存队列里面的数量已满,则新建线程
4.当线程池里面的线程数量大于corePoolSize时,若线程处于空闲状态并且空闲时间超过keepAliveSeconds时,将会回收线程,可以动态的控制线程池里面的线程数量
5.当线程池里面的线程数等于maxPoolSize,并且缓存队列已满,则通过rejectedExecutionHandler设置的处理策略来处理任务;
拒绝策略有以下几种处理方式:
1.ThreadPoolExecutor.AbortPolicy:舍弃任务,并抛出异常
2.ThreadPoolExecutor.DiscardPolicy:舍弃任务,不抛出异常
3.ThreadPoolExecutor.DiscardOldestPolicy:丢弃缓存队列最旧(也就是排在队列前面的任务)的任务,并将此任务添加到缓存队列
4.ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务,(直接在executor处理的线程中执行该任务,若线程已关闭则舍弃该任务)
五、如何判断一个线程是否拥有锁?
java.lang.Thread类下面有一个方法holdsLock(Obj),返回true则表示拥有对象Obj的锁;
六、java中的wait和sleep有什么区别?
这两个方法都会使线程暂停一段时间,wait方法用于线程间的通信,当条件为真并且其他线程被唤醒时会释放锁,而sleep只会释放cpu资源或者让当前线程停止一段时间,但是不会释放锁;
sleep是线程里面的方法,而wait是Object的方法;
sleep不需要被唤醒,而如果wait没有设置时间,则需要被唤醒(notify);
wait依赖synchronized关键字,而sleep不需要;
七、如何保证三个线程按顺序执行?
可以通过线程自带的join方法,join方法指的是等上一个线程执行完成后在执行,比如说三个线程,thread1,thread2,thread3,按1、2、3顺序执行的话,我们可以设置thread3.join(thread2.join(thread1));
或者通过并发类来控制,比如CountDownLatch();
final Thread thread1 = new Thread(new Runnable() {
@SneakyThrows
@Override
public void run() {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+":"+1);
}
});
final Thread thread2 = new Thread(new Runnable() {
@SneakyThrows
@Override
public void run() {
thread1.join();
System.out.println(Thread.currentThread().getName()+":"+2);
}
});
Thread thread3 = new Thread(new Runnable() {
@SneakyThrows
@Override
public void run() {
thread2.join();
System.out.println(Thread.currentThread().getName()+":"+3);
}
});
thread1.start();
thread2.start();
thread3.start();
八、Thread的yield方法有什么用?
Thread执行了yield之后会让掉当前的cpu时间片,然后去重新争夺cpu调度权,可能会获取到cpu调度权并继续执行,也可能获取不到;注意:只会和当前线程同级或者更高级的cpu去竞争cpu的调度权;
public static void thread6(){
Runnable runnable = new Runnable() {
@Override
public void run() {
for (int i=0; i<100; i++){
System.out.println(Thread.currentThread().getName()+":"+i);
if(i%20==0){
Thread.yield();
}
}
}
};
Thread thread1 = new Thread(runnable, "A");
Thread thread2 = new Thread(runnable, "B");
// thread1.setPriority(1);
// thread2.setPriority(5);
thread1.start();
thread2.start();
}
九、sleep和yield的区别和相同点
sleep和yeild都可以让当前线程暂停,不过sleep可以指定暂停时间,yield则依赖cpu时间片的划分
sleep和yield都不会释放锁
sleep可以中断,yield不可以中断;
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/138915.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...