多线程相关
多线程
多个线程同时或交替运行, 单核CPU为顺序执行(交替执行), 多核情况下, 每个CPU有自己的运算器, 所以在多个CPU中可以同时运行.
创建线程的方式
1.继承Thread
public class MyThread extends Thread {
@Override
public void run() {
super.run();
System.out.println(Thread.currentThread().getName() + "执行完毕");
}
}
public class ThreadTest {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.setName("测试");
myThread.start();
System.out.println(Thread.currentThread().getName() + "执行完毕");
}
}
开始线程, 可以看出main线程和测试线程是两个独立的线程
调用myThread.run();方法相当于直接在主线程运行run方法, 而不是开启一个新的线程去执行
2.实现Runnable接口
public class MyRunable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "执行完毕");
}
}
public class ThreadTest {
public static void main(String[] args) {
MyRunable runable = new MyRunable();
Thread thread = new Thread(runable);
thread.start();
System.out.println(Thread.currentThread().getName() + "执行完毕");
}
}
3.使用线程池
3.1 可以在spring中配置相关线程池, 使用时从容器取出即可, 也可以自己声明线程池
<bean id="threadPool" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!-- 核心线程数,默认为1 -->
<property name="corePoolSize" value="5"/>
<!-- 最大线程数,默认为Integer.MAX_VALUE -->
<property name="maxPoolSize" value="20"/>
<!-- 队列最大长度,一般需要设置值>=notifyScheduledMainExecutor.maxNum;默认为Integer.MAX_VALUE
<property name="queueCapacity" value="1000" /> -->
<!-- 线程池维护线程所允许的空闲时间,默认为60s -->
<property name="keepAliveSeconds" value="300"/>
<!-- 队列最大长度 -->
<property name="queueCapacity" value="2000"/>
<!-- 线程池对拒绝任务(无线程可用)的处理策略,目前只支持AbortPolicy、CallerRunsPolicy;默认为后者 -->
<property name="rejectedExecutionHandler">
<!-- AbortPolicy:直接抛出java.utils.concurrent.RejectedExecutionException异常 -->
<!-- CallerRunsPolicy:主线程直接执行该任务,执行完之后尝试添加下一个任务到线程池中,可以有效降低向线程池内添加任务的速度 -->
<!-- DiscardOldestPolicy:抛弃旧的任务、暂不支持;会导致被丢弃的任务无法再次被执行 -->
<!-- DiscardPolicy:抛弃当前任务、暂不支持;会导致被丢弃的任务无法再次被执行 -->
<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy"/>
</property>
</bean>
3.2 Executors 创建线程池
public class ThreadTest {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
threadPool.execute(new MyRunable());
}
}
}
当手动创建线程池时, 如果IDEA安装阿里 P3C 插件后会报错提示以下内容, 建议
线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明: Executors 返回的线程池对象的弊端如下:
1) FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2) CachedThreadPool 和 ScheduledThreadPool:
允许的创建线程数量为 Integer.MAX_VALUE, 可能会创建大量的线程,从而导致 OOM。
建议使用如下方式:
public class ThreadTest {
public static void main(String[] args) {
// 定时任务 建议为线程起名
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(3,
new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").build());
executorService.scheduleAtFixedRate(new MyRunable(), 0, 1, TimeUnit.SECONDS);
}
}
public class ThreadTest {
public static void main(String[] args) {
// 线程工厂
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("demo-pool-%d").build();
//Common Thread Pool
ExecutorService pool = new ThreadPoolExecutor(5, 20, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
pool.execute(()-> System.out.println(Thread.currentThread().getName()));
pool.shutdown();//gracefully shutdown
}
}
线程优先级
1.myThread.setPriority(1);设置优先级
2.优先级从低到高为 1-10, Thread类提供 Thread.MIN_PRIORITY=1, Thread.NORM_PRIORITY=5, Thread.MAX_PRIORITY=10
3.默认优先级为 5 即 NORM_PRIORITY
4.优先级高的仅代表获取进入运行机会的几率大, 并不代表一定会比优先级低的先执行
sleep()和wait()
1.sleep()线程未释放锁, 时间结束后线程继续执行
2.wait线程释放锁, 需要使用notify或notifyAll
3.wait常用于线程之间的交互
package com.liuzhihang.tool.alternate;
/**
* 交替打印奇偶数
*
* @author liuzhihang
* @date 2018/9/4 18:39
*/
public class AlternateNum {
public static void main(String[] args) {
Num num = new Num();
Thread thread1 = new Thread(new Odd(num));
Thread thread2 = new Thread(new Even(num));
thread1.start();
thread2.start();
}
}
class Num {
int anInt = 1;
boolean flag = true;
}
class Odd implements Runnable {
private Num num;
public Odd(Num num) {
this.num = num;
}
@Override
public void run() {
while (num.anInt < 1000) {
// 使用同一把锁
synchronized (num) {
if (num.flag) {
System.out.println("奇数 -> " + num.anInt);
num.anInt++;
num.flag = false;
num.notify();
} else {
try {
num.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
class Even implements Runnable {
private Num num;
public Even(Num num) {
this.num = num;
}
@Override
public void run() {
while (num.anInt < 1000) {
// 使用同一把锁
synchronized (num) {
if (!num.flag) {
System.out.println("偶数 -> " + num.anInt);
num.anInt++;
num.flag = true;
num.notify();
} else {
try {
num.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 程序员小航
评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果