Java多线程的几种方式
1、继承Thread类或实现Runable接口
异步执行类:
//异步执行类
public class SyncTask {
public void task(MyCallBack myCallBack) {
Thread thread = new Thread(new Runnable() {
//重写run方法
@Override
public void run() {
long time = System.currentTimeMillis();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
//回调结果
myCallBack.callBack(sum);
System.out.println("子线程耗时:" + (System.currentTimeMillis() - time));
}
});
//开启线程
thread.start();
}
}
回调接口:
//回调接口,用于回调结果
public interface MyCallBack {
void callBack(Object object);
}
测试类:
//测试类
public class Test {
public static void main(String[] args) {
long time = System.currentTimeMillis();
//异步执行
new SyncTask().task(new MyCallBack() {
//重新回调函数
@Override
public void callBack(Object object) {
System.out.println("异步回调值:" + object);
}
});
System.out.println("主线程等待异步输出");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程耗时:" + (System.currentTimeMillis() - time));
}
}
结果:
不建议单纯使用继承Thread或者实现Runnable接口的方式来创建线程,那样势必有创建及销毁线程耗费资源、线程上下文切换问题,这个时候引入线程池比较合理。
2、使用Executors
ThreadPoolExecutor提供了四个构造方法:
第四个ThreadPoolExecutor构造函数的源码如下:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
@NotNull java.util.concurrent.TimeUnit unit,
@NotNull java.util.concurrent.BlockingQueue<Runnable> workQueue)
解释各参数:
序号 | 名称 | 类型 | 含义 |
---|---|---|---|
1 | corePoolSize | int | 核心线程池大小 |
2 | maximumPoolSize | int | 最大线程池大小 |
3 | keepAliveTime | long | 线程最大空闲时间 |
4 | unit | TimeUnit | 时间单位 |
5 | workQueue | BlockingQueue | 线程等待队列 |
6 | threadFactory | ThreadFactory | 线程创建工厂 |
7 | handler | RejectedExecutionHandler | 拒绝策略 |
预定义线程池
1、ThreadPoolExecutor
newFixedThreadPool的源码如下:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
可以看出newFixedThreadPool是通过调用ThreadPoolExecutor来创建线程池的,而newFixedThreadPool也存在一下特点:
- corePoolSize与maximumPoolSize相等,即其线程全为核心线程,是一个固定大小的线程池;
- keepAliveTime = 0 该参数默认对核心线程无效,而FixedThreadPool全部为核心线程;
- workQueue 为LinkedBlockingQueue(无界阻塞队列),队列最大值为Integer.MAX_VALUE。如果任务提交速度持续大余任务处理速度,会造成队列大量阻塞。因为队列很大,很有可能在拒绝策略前,内存溢出;
- FixedThreadPool的任务执行是无序的。
具体实现,修改SyncTask类:
public class SyncTask {
public void task(MyCallBack myCallBack) {
//引入线程池
ExecutorService pool = Executors.newFixedThreadPool(10);
pool.execute(new Runnable() {
@Override
public void run() {
long time = System.currentTimeMillis();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
myCallBack.callBack(sum);
System.out.println("子线程耗时:" + (System.currentTimeMillis() - time));
}
});
}
}
结果:
2、CachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
- corePoolSize = 0,maximumPoolSize = Integer.MAX_VALUE,即线程数量几乎无限制;
- keepAliveTime = 60s,线程空闲60s后自动结束。
- workQueue 为 SynchronousQueue 同步队列,这个队列类似于一个接力棒,入队出队必须同时传递,因为CachedThreadPool线程创建无限制,不会有队列等待,所以使用SynchronousQueue;
3、SingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
4、ScheduledThreadPool
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
自定义线程池
通过自定义ThreadPoolExecutor来创建线程池:
public class SyncTest {
public static void main(String[] args) throws InterruptedException, IOException {
int corePoolSize = 2;
int maximumPoolSize = 4;
long keepAliveTime = 10;
TimeUnit unit = TimeUnit.SECONDS;
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2);
ThreadFactory threadFactory = new NameTreadFactory();
RejectedExecutionHandler handler = new MyIgnorePolicy();
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit,
workQueue, threadFactory, handler);
executor.prestartAllCoreThreads(); // 预启动所有核心线程
for (int i = 1; i <= 10; i++) {
MyTask task = new MyTask(String.valueOf(i));
executor.execute(task);
}
System.in.read(); //阻塞主线程
}
static class NameTreadFactory implements ThreadFactory {
private final AtomicInteger mThreadNum = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "my-thread-" + mThreadNum.getAndIncrement());
System.out.println(t.getName() + " has been created");
return t;
}
}
public static class MyIgnorePolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
doLog(r, e);
}
private void doLog(Runnable r, ThreadPoolExecutor e) {
// 可做日志记录等
System.err.println( r.toString() + " rejected");
// System.out.println("completedTaskCount: " + e.getCompletedTaskCount());
}
}
static class MyTask implements Runnable {
private String name;
public MyTask(String name) {
this.name = name;
}
@Override
public void run() {
try {
System.out.println(this.toString() + " is running!");
Thread.sleep(3000); //让任务执行慢点
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public String getName() {
return name;
}
@Override
public String toString() {
return "MyTask [name=" + name + "]";
}
}
}
结果:
3、使用spring线程池ThreadPoolTaskExecutor
<!-- 异步线程池 -->
<bean id="threadPool" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!-- 核心线程数 -->
<property name="corePoolSize" value="2"/>
<!-- 最大线程数 -->
<property name="maxPoolSize" value="3"/>
<!-- 队列最大长度 -->
<property name="queueCapacity" value="10"/>
<!-- 线程池维护线程所允许的空闲时间 -->
<property name="keepAliveSeconds" value="300"/>
<!-- 线程池对拒绝任务(无线程可用)的处理策略 -->
<property name="rejectedExecutionHandler">
<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunPolicy"/>
</property>
</bean>
public class SyncTask {
@Autowired
private ThreadPoolTaskExecutor poolExecutor;
public void task(MyCallBack myCallBack) {
poolExecutor.execute(new Runnable() {
@Override
public void run() {
long time = System.currentTimeMillis();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
myCallBack.callBack(sum);
System.out.println("子线程耗时:" + (System.currentTimeMillis() - time));
}
});
}
}