线程和线程池的创建及使用

7 篇文章 0 订阅

  三种创建线程的方法

一、通过继承 Thread 类本身

public class MyThread extends Thread {
    @Override
    public void run(){
        super.run();
        System.out.println("执行子线程...");
    }
}
public class Test {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
        System.out.println("主线程...");
    }
}

二、通过实现 Runnable 接口

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("执行子线程...");
    }
}
public class Test {
    public static void main(String[] args) {
        Runnable runnable = new MyRunnable();
        Thread thread = new Thread(runnable);
        thread.start();
        System.out.println("主线程运行结束!");
    }
}

三、通过 Callable 和 Future 创建线程

public class MyCallable implements Callable {
    int i = 0;
    @Override
    public Object call() throws Exception {
        System.out.println(Thread.currentThread().getName()+"  i的值:"+ i);
        return i++; //call方法可以有返回值
    }
}
public class Test {
    public static void main(String[] args) {
        Callable callable = new MyCallable();
        for (int i = 0; i < 10; i++) {
            FutureTask task = new FutureTask(callable);
            new Thread(task,"子线程"+ i).start();
            try {
                //获取子线程的返回值
                System.out.println("子线程返回值:"+task.get() + "\n");
            }  catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

第一种和后面两种的对比:1、 通过代码可以看出,第一种方法是最简洁方便的,直接就可以start,不需要任何转换 2、但是第一种有一个很不好的地方就是继承了Thread类后由于java的单继承机制,就不      可以继承其他的类了,而如果实现的是接口,就可以实现多个接口,使开发更灵活

第二种和第三种方式对比:1、同样的,第二种方法相对第三种方式来说代码更简洁,使用更方便,少了一次转换 2、第三种方法有两个优点:有返回值、可以抛出异常

总结:实际开发中可能有更复杂的代码实现,需要继承其他的类,所以平时更推荐通过实现接 口来实现多线程,也就是通过第二或第三种方式来实现,这样能保持代码灵活和解耦。 而选择第二还是第三种方式,则要根据run()方法是不是需要返回值或者捕获异常来决定, 如果不需要,可以选择用第二种方式实现,代码更简洁。

线程池

       上述常见的创建线程的方法,一种是继承Thread类,一种是实现Runnable的接口,Thread类其实也是实现了Runnable接口。但是我们创建这两种线程在运行结束后都会被虚拟机销毁,如果线程数量多的话,频繁的创建和销毁线程会大大浪费时间和效率,更重要的是浪费内存,因为正常来说线程执行完毕后死亡,线程对象变成垃圾!那么有没有一种方法能让线程运行完后不立即销毁,而是让线程重复使用,继续执行其他的任务哪?我们使用线程池就能很好地解决这个问题。

  1. 减少创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。

  2. 可以根据系统的承受能力,调整线程池中工作线程的数目,放置因为消耗过多的内存,而把服务器累趴下(每个线程大约需要 1 MB 内存,线程开的越多,消耗的内存也就越大,最后死机)

使用Executors类中提供的几个静态方法来创建线程池,内部实现均使用了 ThreadPoolExecutor 实现,其实都只是ThreadPoolExecutor 类的封装:

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

函数的参数含义如下:

  • corePoolSize:指定了线程池中的线程数量
  • maximumPoolSize:指定了线程池中的最大线程数量
  • keepAliveTime:当线程池线程数量超过 corePoolSize 时,多余的空闲线程的存活时间。即,超过了 corePoolSize 的空闲线程,在多长时间内,会被销毁。
  • unit: keepAliveTime 的单位。
  • workQueue:任务队列,被提交但尚未被执行的任务。
  • threadFactory:线程工厂,用于创建线程,一般用默认的即可。
  • handler:拒绝策略。当任务太多来不及处理,如何拒绝任务。

 线程池内部维护的工作者线程的数量就是该线程池的线程池大小,有 3 种形态:

  1. 如果运行的线程少于 corePoolSize,则 Executor 始终首选添加新的线程,而不进行排队;

  2. 如果运行的线程等于或者多于 corePoolSize,则 Executor 始终首选将请求加入队列,而不是添加新线程;

  3. 如果无法将请求加入队列,即队列已经满了,则创建新的线程,除非创建此线程超出 maxinumPoolSize, 在这种情况下,任务将被拒绝。(拒绝后的处理有四种,如下图)

       

工作线程数量可以理解为高速上的入口通道,比如高速入口共有8个通道,正常开放4个(corePoolSize),如果只有三辆车,每辆车都可以分别走一个通道,如果有五辆车,这第五辆车排队等待,而不是加开一个通道。如果车辆很多导致排队队伍过长,则需要加开通道直到所有8个通道(maxinumPoolSize)全开。如果通道全开且排队队伍已满,则关闭高速入口,后面的车辆需要绕行(任务将被拒绝)。

线程池创建示例:

  1. Executors.newCachedThreadPool();        //创建一个缓冲池,缓冲池容量大小为Integer.MAX_VALUE
  2. Executors.newSingleThreadExecutor();   //创建容量为1的缓冲池
  3. Executors.newFixedThreadPool(int maximumPoolSize);    //创建固定容量大小的缓冲池
  4. Executors.newScheduledThreadPool(int corePoolSize); // 固定线程数,支持定时和周期性任务
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE,
          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
          new DelayedWorkQueue());
}
ExecutorService cachePool = Executors.newCachedThreadPool();
ExecutorService singlePool = Executors.newSingleThreadExecutor();
ExecutorService fixedPool = Executors.newFixedThreadPool(int);
ExecutorService scheduledPool = Executors.newScheduledThreadPool(5);

ExecutorService myExecutor = new ThreadPoolExecutor(4, 5, 0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(1000));

    自定义的线程名

//自定义线程名称
    static class DIYThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        DIYThreadFactory(String diyName) {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                    Thread.currentThread().getThreadGroup();
            namePrefix = diyName +
                    "-thread-";
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                    namePrefix + threadNumber.getAndIncrement(),
                    0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }
 private static ExecutorService myExecutor = Executors.newFixedThreadPool(10,new DIYThreadFactory("XXX"));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值