文章目录
创建线程的四种方法
1. 继承Thread类创建线程
static class MyThread extends Thread {
@Override
public void run() {
}
}
public static void mian (String[] args) {
Thread t = new MyThread();
t.start();
}
2. 实现Runnable接口创建线程
public static void main (String[] args) {
Thread t = new Thread(new Runnable () {
@Override
public void run() {
}
});
t.start();
}
3.实现Callable接口创建线程
Callable接口和Runnable接口最大的区别就是我们Callable接口中的call()方法是带返回值的方法
-
我们实现Callable接口的创建
-
使用FutureTask来包裹这个Callable接口 注意的是,FutureTasK所存储的类型和call()方法返回的类型是一致的。
-
创建Thread 包裹这个FutureTask 创建好一个线程
static class MyCallable implents Callable() { @Override public Integer call() throws Exception { System.out.println("xxx"); return 0; } } public static void main(String[] args) { // 第一种方式 Thread t = new Thread(new FutureTask<String>(new Callable<String>() { @Override public String call() throws Exception { System.out.println("xxx"); return null; } })); t.start(); // 第二种方式 MyCallable c = new MyCallable(); FutureTask<Integer> f = new FutureTask<>(c); Thread t2 = new Thread(f); t2.start(); // 获取返回值 System.out.println(f.get()); }
4.使用线程池创建线程
1.对比new Thread,创建线程都比较耗时,使用线程池可以达到线程复用的目的。
2. 创建线程池的方式:
-
创建JDK提供的四种线程池:固定大小, 单线程,缓存的,计划任务的。不建议生产使用
ExecutorService p1 = Executors.newCachedThreadPool(); // 缓存线程池 ExecutorService p2 = Executors.newFixedThreadPool(2);//固定线程池 ExecutorService p3 = Executors.newScheduledThreadPool(3);//计划任务的线程池 ExecutorService p4 = Executors.newSingleThreadExecutor();// 单线程的线程池 public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory); } public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } public static ScheduledExecutorService newScheduledThreadPool( int corePoolSize, ThreadFactory threadFactory) { return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); } public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory)); } -
建议方式 new ThreadPoolExecutor()
public ThreadPoolExecutor(int corePoolSize, // 核心线程数 int maximumPoolSize, // 最大线程数 long keepAliveTime, // 非核心线程存活时间 TimeUnit unit, // 非核心线程存活时间的单位 BlockingQueue<Runnable> workQueue, // 阻塞队列 ThreadFactory threadFactory,// 线程工厂 RejectedExecutionHandler handler // 拒绝策略 ) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }- 创建一个线程池
ThreadPoolExecutor p = new ThreadPoolExecutor(3, 5, Runtime.getRuntime().availableProcessors(),//获取本机cpu核数 TimeUnit.SECONDS, new LinkedBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy() );- 线程池的拒绝策略
(1)ThreadPoolExecutor.AbortPolicy 丢弃任务,并抛出 RejectedExecutionException 异常。
(2)ThreadPoolExecutor.CallerRunsPolicy:该任务被线程池拒绝,由调用execute方法的线程执行该任务。
(3)ThreadPoolExecutor.DiscardOldestPolicy : 抛弃队列最前面的任务,然后重新尝试执行任务。
(4)ThreadPoolExecutor.DiscardPolicy,丢弃任务,不过也不抛出异常。
3. 通过线程池创建任务
-
submit()
c传入的参数可以为 Callable ,Runnable,Runnable和泛型T

它的返回值是一个Future对象

-
execute()
传入的参数是 Runnable对象 ,并且无返回值
-
如果运行的线程少于corePoolSize,请尝试以给定的命令作为第一个线程开始一个新线程任务。对addWorker的调用以原子方式检查运行状态和workerCount,从而防止会增加当它不应该的时候,返回false。
-
如果任务可以成功排队,那么我们仍然需要仔细检查是否应该添加线程(因为自从上次检查以来已有的已经死了)或者自进入此方法后,池已关闭。所以我们重新检查状态,必要时回滚排队已停止,如果没有,则启动新线程。
-
如果无法将任务排队,则尝试添加新的线程。如果失败了,我们就知道我们已经关闭或者饱和了
所以拒绝这个任务。
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); /* * Proceed in 3 steps: * * 1. If fewer than corePoolSize threads are running, try to * start a new thread with the given command as its first * task. The call to addWorker atomically checks runState and * workerCount, and so prevents false alarms that would add * threads when it shouldn't, by returning false. * * 2. If a task can be successfully queued, then we still need * to double-check whether we should have added a thread * (because existing ones died since last checking) or that * the pool shut down since entry into this method. So we * recheck state and if necessary roll back the enqueuing if * stopped, or start a new thread if there are none. * * 3. If we cannot queue task, then we try to add a new * thread. If it fails, we know we are shut down or saturated * and so reject the task. */ int c = ctl.get(); if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); } if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); if (! isRunning(recheck) && remove(command)) reject(command); else if (workerCountOf(recheck) == 0) addWorker(null, false); } else if (!addWorker(command, false)) reject(command); } -
自己实现一个线程池
```java
package 线程池;
//包含一些线程,避免我们去频繁创建/销毁线程的开销
//核心操作 execute 把一个任务加到线程池中
// shutdown 销毁线程池中的所有线程
//组成部分
// 管理两个内容,要执行的任务,执行任务的线程们
// 有一个类,来描述具体线程要做的工作是啥
// 一个数据结构组织任务,阻塞队列
// 一个类,表示工作线程
// 一个数据结构,组织若干个线程
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class Test1 {
//使用这个类来描述当前的工作线程
static class Worker extends Thread {
private int id = 0;
private BlockingQueue<Runnable> queue = null;
public Worker(BlockingQueue<Runnable> queue, int id) {
this.queue = queue;
this.id = id;
}
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Runnable c = queue.take();
System.out.println("Thread" + id + "Running");
c.run();
} catch (InterruptedException e) {
//线程被结束
System.out.println("线程被终止");
}
}
}
}
static class MyThreadPool {
//一个阻塞队列用来组织若干个任务
private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
//一个list用来组织若干个工作线程
private List<Worker> workers = new ArrayList<>();
//定义线程池内应该有多少个线程,随便定义
private static final int maxThread = 10;
//相当于往线程池中添加线程
public void execute(Runnable c) throws InterruptedException {
if (workers.size() < maxThread) {
Worker worker = new Worker(queue, workers.size());
worker.start();
workers.add(worker);
}
queue.put(c);
}
//shutdown,意味着所有的线程结束了
public void shutDown() throws InterruptedException {
//中断所有线程
for (Worker w: workers
) {
w.interrupt();
}
//这个线程执行完后才可以中断
for (Worker w: workers
) {
w.join();
}
}
}
}
``
本文详细介绍了Java中创建线程的四种方法:继承Thread类、实现Runnable接口、实现Callable接口和使用线程池。重点讨论了线程池的使用,包括JDK提供的四种线程池类型和自定义线程池,以及线程池的拒绝策略。通过实例展示了如何创建线程池并提交任务,阐述了线程池在提高系统效率和资源管理上的优势。
1555

被折叠的 条评论
为什么被折叠?



