线程的创建
1. 线程的创建方式
- 继承Thread
- 实现Runnble接口
- 实现callable接口
- 线程池创建
2. 继承Thread类
2.1 实现方式
- 创建一个继承于Thread类的子类
- 重写Thread类的run() —> 将此线程执行的操作声明在run()中
- 创建Thread类的子类的对象
通过此对象调用start():①启动当前线程 ② 调用当前线程的run()
2.2 代码示例
public class extendsThread {
public static void main(String[] args) {
// 3、new Thread对象
exThread exThread = new exThread();
// 4、调用start()启动线程
exThread.start();
}
}
// 1、继承Thread类
class exThread extends Thread {
@Override
// 2、重写run方法
public void run() {
System.out.println("使用继承Thread类,来创建线程");
}
}
3. 实现Runnable接口
3.1 实现方式
创建一个实现Runnable接口的类
- 覆写run()方法
- 创建实现类的对象
- 将此对象作为参数传递到Thread类的构造器中,创建Thread对象
- 通过Thread类的对象调用start()
3.2 代码示例
/**
* @author zongzhaojin
* @date 2022/4/16 11:12
*/
public class RunnableTest {
public static void main(String[] args) {
// 3. 创建实现类
GetRunnable getRunnable = new GetRunnable();
// 4. 新建Thread对象,将实现类传入
Thread thread = new Thread(getRunnable);
// 5. 调用Thread对象的start()方法
thread.start();
}
}
// 1. 实现Runnable接口
class GetRunnable implements Runnable{
// 2. 重写Run方法
@Override
public void run() {
System.out.println("通过实现Runnable接口来创建一个线程");
}
}
3. 实现Callable接口
3.1 实现方式
- 创建一个实现Callable的实现类
- 实现call方法
- 创建实现类对象
- 将实现类传入FutureTask构造器中,创建FutureTask的对象
- 将FutureTask的对象传入Thread类构造器中,创建Thread对象,并调用start()
-
3.2 代码示例
/** * @author zongzhaojin * @date 2022/4/15 19:11 */ public class callThread { public static void main(String[] args) { // 3. 创建实现类的对象 MyThread myThread = new MyThread(); // 4.将实现类对象传入FutureTask构造函数中 创建FutureTask对象 支持泛型 FutureTask<String> futureTask = new FutureTask(myThread); // 5. 将futureTask对象传入Thread构造器中 创建对象 并调用start()方法 new Thread(futureTask).start(); try { String str = futureTask.get(); System.out.println(str); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } // 1.实现Callable接口 class MyThread implements Callable{ // 2. 实现call方法 @Override public Object call() throws Exception { for(int i = 0;i<10;i++){ System.out.println(i); } return "成功返回"; } }
4. 使用线程池来创建线程
4.1 线程池的参数
corePoolSize: 核心线程数量,当有新任务在execute()方法提交时,会执行以下判断:
- 如果运行的线程少于corePoolSize,则创建新线程来处理任务,即使线程池中的其他线程是空闲的
- 如果线程池中的线程数量大于等于corePoolSize且小于maximumPoolSize,则只有当workQueue满时才创建新的线程去处理任务
- 如果corePoolSize和maximumPoolSize相同,则创建的线程池大小是固定的,这时如果有新任务提交,若workQueue未满,则将请求放入workQueue中,等待有空闲的线程去从workQueue中取任务并处理
- 如果运行的线程数量大于等于maximumPoolSize,这时候workQueue已经满了,则通过handler所指定的策略来处理任务;
所以,在任务提交时,判断的顺序为 corepoolSize —> workQueue —> maximumPoolSize
- maximumPoolSize: 最大线程数量
- workQueue: 等待队列,当任务提交时,如果线程池中的线程数量大于等于corePoolSize的时候,把任务封装成一个Worker对象放入等待队列;workQueue 主要有以下几种处理方式:
- 直接切换:这种方式常用的队列是SynchronousQueue
- 无界队列:一般使用基于链表的阻塞队列LinkedBlockIngQueue。如果使用这种方式,那么线程池能够创建的最大线程数就是corePoolSize。而maximumPoolSize就不会起作用了。
- 有界队列:一帮使用ArrayBlockingQueue,使用该方式可以将线程池的最大线程数量限制为maximumPoolSize,这样能够降低资源的消耗,但是需要注意如果worker足够多,会频繁调用handler策略
- keepAliveTime: 线程池维护线程允许的空闲时间。当线程池中的线程数量大于corePoolSize的时候,如果没有新的任务提交,核心线程外的线程不会立即销毁,二十等待,直到等待时间超过keepAliveTime,在进行销毁。
- threadFactory: 它是ThreadFactory类型的变量,用来创建新线程。默认是使用
Executors.defaultThreadFactory()
来创建线程。使用默认的ThreadFactory来创建线程时,会使新创建的线程具有相同的NORM_PRIORITY优先级并且是非守护线程,同时也设置了线程的名称。 - handler: 它是RejectedExecutionHandler类型的变量,表示线程池的饱和策略。如果阻塞队列满了并且没有空闲的线程,这时如果继续提交任务,就需要采取一种策略处理该任务。线程池提供了4种策略:
- AbortPolicy: 直接抛出异常,这是默认策略;
- CallerRunsPolicy: 用调用者所在的线程来执行任务
- DiscardOldestPolicy: 丢弃阻塞队列中最靠前的任务,并执行当前任务;
- DiscardPolicy:直接丢弃任务
TimeUnit: 存活时间的单位:
TimeUnit.DAYS; //天 TimeUnit.HOURS; //小时 TimeUnit.MINUTES; //分钟 TimeUnit.SECONDS; //秒 TimeUnit.MILLISECONDS; //毫秒 TimeUnit.MICROSECONDS; //微妙 TimeUnit.NANOSECONDS; //纳秒
4.2 实现方式
实现Runnable接口
- 实现Run方法
- 构造ThreadPoolExecutor对象
调用ThreadPoolExecutor的对象的execute()方法 ,将实现Runnable的对象当做参数传入
4.3 代码示例
```java /**
- @author zongzhaojin
@date 2022/4/16 11:31 */ public class ThreadPool { public static void main(String[] args) throws InterruptedException { int corePoolSize = 5; int maximumPoolSize = 10; int keepAliveTime = 10; TimeUnit timeUnit = TimeUnit.SECONDS; ArrayBlockingQueue
arrayBlockingQueue = new ArrayBlockingQueue (100); ThreadFactory threadFactory = Executors.defaultThreadFactory(); RejectedExecutionHandler defaultHandler = new ThreadPoolExecutor.AbortPolicy(); // 3 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, timeUnit, arrayBlockingQueue, threadFactory, defaultHandler); for(int i = 0;i<1000;i++){ // Thread.sleep(10); // 4 threadPoolExecutor.execute(new RunnableDemo(i));
}
} } // 1 class RunnableDemo implements Runnable { int num; public RunnableDemo(int num){ this.num = num; } // 2 @Override public void run() { System.out.println(“第”+num+”次: “+Thread.currentThread().getName()+”: hello ThreadPool”); } }
```