一、概述
在java中,无论是并发还是并行都离不开多线程编程,而线程的创建和使用就是这一切的开始。以下是在工作中线程的创建和使用的总结
二、Thread 和 Runnable
2.1 Thread(不推荐使用)
线程的创建一开始就是通过继承Thread类,通过重写run()方法,来实现多线程启动任务的方法,它的缺点很明显不能进行多继承,以下是代码的实现:
public class ExtThread extends Thread{
public ExtThread(){}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+",run....");
}
public static void main(String[] args) {
ExtThread t1 = new ExtThread();
ExtThread t2 = new ExtThread();
ExtThread t3 = new ExtThread();
ExtThread t4 = new ExtThread();
t1.start();
t2.start();
t3.start();
t4.start();
}
}
2.2 Runnable
通过实现Runnable接口,间接的实现多线程的编写。
为什么说间接实现?
因为,如果不通过new Thread()的方式,它还是一个普通的类,不是一个单独运行的线程。
以下是代码的实现:
public class ImpleRunnable implements Runnable {
int count = 20;
@Override
public void run() {
count--;
System.out.println(Thread.currentThread().getName()+",run....,count = "+count);
}
public static void main(String[] args) {
Thread t1 = new Thread(new ImpleRunnable());
Thread t2 = new Thread(new ImpleRunnable());
Thread t3 = new Thread(new ImpleRunnable());
Thread t4 = new Thread(new ImpleRunnable());
t1.start();
t2.start();
t3.start();
t4.start();
}
}
2.3 Callable
Callable接口与Runnable接口是非常相似的,但是Callable接口是一种带有返回值的线程实现方式,它启动的线程的方式也是与Runnable接口不同,本质来说Callable接口是通过启动另一个线程来获取返回值的,程序会创建两个线程来执行Callable接口的逻辑。
以下是代码的实现:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ImpleCallable implements Callable<String> {
int count = 20;
@Override
public String call() throws Exception {
count--;
System.out.println(Thread.currentThread().getName()+",run....,count = "+count);
return Thread.currentThread().getName();
}
//只有第一个线程执行了任务
public static void main(String[] args) throws InterruptedException, ExecutionException {
//使用Callable接口和Runnable,除了有返回值外,
//还是有一定的区别
Callable<String> callable = new ImpleCallable();
FutureTask<String> futureTask = new FutureTask<>(callable);
//定义三个线程进行启动,结果只有一个线程执行了任务
/**
* FutureTask.run()执行的时候
* if (state != NEW ||
* !UNSAFE.compareAndSwapObject(this, runnerOffset,
* null, Thread.currentThread()))
* future在执行的时候,会判断该线程是否处于初始化状态
* 所以下面只有一个线程会执行成功,其余线程不会在进行执行,
* 如果需要执行多个任务,就需要实例化多个FutureTask
*/
Thread mThread = new Thread(futureTask);
Thread mThread2 = new Thread(futureTask);
Thread mThread3 = new Thread(futureTask);
mThread.start();
mThread2.start();
mThread3.start();
System.out.println(futureTask.get());
}
}
2.4 线程池(推荐)
传统的实现多线程的形式有一个弊端:
- 线程不能被复用
- 不能控制线程的并发数
- 不能管理线程
使用线程池能很好解决以上的问题,从而提高系统的稳定性和效率,
2.4.1 ThreadPoolExecutor
ThreadPoolExecutor这是一个功能很齐全的线程池,只要通过理解它的七个参数基本就能掌握这个线程池的使用:
public ThreadPoolExecutor(int corePoolSize, //核心线程数量
int maximumPoolSize,//最大线程数
//当池中线程数大于核心线程数时,该时间为余下线程(存活线程总数-核心线程数)的最大空闲存活时间
long keepAliveTime,
TimeUnit unit,//时间单位
BlockingQueue<Runnable> workQueue,//工作队列
ThreadFactory threadFactory,//创建线程的线程工厂
RejectedExecutionHandler handler)//拒绝策略
这7个参数中,平常最多用到的是corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue.在这里我主抽出corePoolSize、maximumPoolSize和workQueue三个参数进行详解。
maximumPoolSize(最大线程数) = corePoolSize(核心线程数) + noCorePoolSize(非核心线程数);
- 当currentSize<corePoolSize时,没什么好说的,直接启动一个核心线程并执行任务。
- 当currentSize>=corePoolSize、并且workQueue未满时,添加进来的任务会被安排到workQueue中等待执行。
- 当workQueue已满,但是currentSize<maximumPoolSize时,会立即开启一个非核心线程来执行任务。
- 当currentSize>=corePoolSize、workQueue已满、并且currentSize>maximumPoolSize时,调用handler默认抛出RejectExecutionExpection异常。
2.4.1 其它线程池的现实
实现代码如下:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 使用线程池运行线程,一共有五种线程池
* 1. newFixedThreadPool
* 2. newWorkStealingPool
* 3. newSingleThreadExecutor
* 4. newCachedThreadPool
* 5. newScheduledThreadPool
*/
public class TestThreadPool {
public static void main(String[] args) throws Exception{
//TestThreadPool.testNewFixedThreadPool();
//TestThreadPool.testNewSingleThreadExecutor();
//TestThreadPool.testNewCachedThreadPool();
//TestThreadPool.testNewScheduledThreadPool();
TestThreadPool.testNewWorkStealingPool();
}
//配置线程池,创建一个固定线程的线程池
public static void testNewFixedThreadPool(){
ExecutorService ex = Executors.newFixedThreadPool(10);
runMethod(ex);
ex.shutdown();
}
//单线程池
public static void testNewSingleThreadExecutor(){
ExecutorService ex = Executors.newSingleThreadExecutor();
runMethod(ex);
ex.shutdown();
}
//缓存线程池 - 无限制创建线程
public static void testNewCachedThreadPool(){
ExecutorService ex = Executors.newCachedThreadPool();
runMethod(ex);
ex.shutdown();
}
public static void runMethod(ExecutorService ex){
for(int i = 0;i < 5;i++) {
ex.submit(new Runnable() {
@Override
public void run() {
for(int j = 0;j < 10;j++) {
System.out.println(Thread.currentThread().getName()+j);
}
}
});
}
}
//newScheduledThreadPool - 定时任务
public static void testNewScheduledThreadPool() throws InterruptedException {
ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
//创建一个定时任务,
//开始一秒后执行任务,然后每隔3秒执行一次任务
service.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
System.out.println("Hello world!");
}
},1,3, TimeUnit.SECONDS);
TimeUnit.SECONDS.sleep(100);
service.shutdown();
}
//newWorkStealingPool - ForkJoin
public static void testNewWorkStealingPool(){
ExecutorService service = Executors.newWorkStealingPool();
runMethod(service);
service.shutdown();
}
}
网友评论