创建线程的四种方式

本文详细介绍了Java中创建线程的四种方法:继承Thread类、实现Runnable接口、实现Callable接口和使用线程池。重点讨论了线程池的使用,包括JDK提供的四种线程池类型和自定义线程池,以及线程池的拒绝策略。通过实例展示了如何创建线程池并提交任务,阐述了线程池在提高系统效率和资源管理上的优势。

创建线程的四种方法
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()方法是带返回值的方法

  1. 我们实现Callable接口的创建

  2. 使用FutureTask来包裹这个Callable接口 注意的是,FutureTasK所存储的类型和call()方法返回的类型是一致的。

  3. 创建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. 创建线程池的方式:
  1. 创建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));
        }
    
    
    
  2. 建议方式 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;
        }
    
    1. 创建一个线程池
     ThreadPoolExecutor p = new ThreadPoolExecutor(3,
                    5,
                    Runtime.getRuntime().availableProcessors(),//获取本机cpu核数
                    TimeUnit.SECONDS,
                    new LinkedBlockingQueue<>(3),
                    Executors.defaultThreadFactory(),
                    new ThreadPoolExecutor.AbortPolicy()
            );
    
    1. 线程池的拒绝策略

    (1)ThreadPoolExecutor.AbortPolicy 丢弃任务,并抛出 RejectedExecutionException 异常。

    (2)ThreadPoolExecutor.CallerRunsPolicy:该任务被线程池拒绝,由调用execute方法的线程执行该任务。

    (3)ThreadPoolExecutor.DiscardOldestPolicy : 抛弃队列最前面的任务,然后重新尝试执行任务。

    (4)ThreadPoolExecutor.DiscardPolicy,丢弃任务,不过也不抛出异常。

3. 通过线程池创建任务
  1. submit()

    c传入的参数可以为 Callable ,Runnable,Runnable和泛型T
    在这里插入图片描述

    它的返回值是一个Future对象
    在这里插入图片描述

  2. execute()

    传入的参数是 Runnable对象 ,并且无返回值

    1. 如果运行的线程少于corePoolSize,请尝试以给定的命令作为第一个线程开始一个新线程任务。对addWorker的调用以原子方式检查运行状态和workerCount,从而防止会增加当它不应该的时候,返回false。

    2. 如果任务可以成功排队,那么我们仍然需要仔细检查是否应该添加线程(因为自从上次检查以来已有的已经死了)或者自进入此方法后,池已关闭。所以我们重新检查状态,必要时回滚排队已停止,如果没有,则启动新线程。

    3. 如果无法将任务排队,则尝试添加新的线程。如果失败了,我们就知道我们已经关闭或者饱和了

    所以拒绝这个任务。

     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();
            }
        }
    }
}

``
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值