创建线程的方式以及Executors的四种线程池

10 篇文章 0 订阅

创建线程有几种方式?
面试常问的问题,一般回答3种方式,及格;如果你能具体的说4种,那你就满分了,第四种是通过Executors创建线程池。

先来说说创建线程的3种方式:

一、继承Thread类

public class ExtendsThread extends Thread {

    @Override
    public void run() {
        super.run();
        Log.e("ExtendsThread >>> ", "thread running");
    }
}
public class MainActivity {

	public static void main(String[] args) {
		ExtendsThread thread = new ExtendsThread();
		thread.start();
	}
}

输出结果:

E/ExtendsThread >>>: thread running

二、实现Runnable接口

public class RunnableImp implements Runnable {
    @Override
    public void run() {
        Log.e("RunnableImp >>> ", "runnable running");
    }
}
public class MainActivity {

	public static void main(String[] args) {
		RunnableImp runnableImp = new RunnableImp();
        new Thread(runnableImp).start();
	}
}

输出结果:

E/RunnableImp >>>: runnable running

三、实现Callable接口

public class CallableImp implements Callable<String> {

    @Override
    public String call() throws Exception {
        Thread.sleep(3000);
        Log.e("CallableImp >>> ", "Callable running");
        return "I`m CallableImp";
    }
}
public class MainActivity {

	public static void main(String[] args) {
		// 3、实现Callable接口
        try {
            CallableImp callableImp = new CallableImp();
            FutureTask<String> futureTask = new FutureTask<>(callableImp);
            new Thread(futureTask).start();
            // 如果CallableImp中任务未执行完,get()方法会阻塞
            Log.e("CallableImp 返回结果 >>> ", futureTask.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
	}
}

输出结果:

E/CallableImp >>>: Callable running
E/CallableImp 返回结果 >>>: I`m CallableImp

Runnable和Callable区别:
Runnable:
1、run方法没有返回值;
2、可以作为Thread的目标对象;
3、run方法不能抛出异常;

Callable:
1、call方法有返回值,通过FutureTask.get()方法获取,如果调用get方法时call方法没有执行完,get方法会阻塞;
2、不能作为Thread的目标对象,RunnableFuture才可以,因为RunnableFuture是一个继承了Runnable和Future的接口,FutureTask是RunnableFuture的一个实现类,一般用FutureTask结合Callable使用;
3、call方法可以抛出异常;

四、Executors创建线程池

1、CachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

private void cachedThreadPool() {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            cachedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("CachedThreadPool >> running " + index + ", Thread = " + Thread.currentThread().toString());
                    try {
                        Thread.sleep(1000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

打印结果:

CachedThreadPool >> running 0, Thread = Thread[pool-1-thread-1,5,main]
CachedThreadPool >> running 1, Thread = Thread[pool-1-thread-2,5,main]
CachedThreadPool >> running 2, Thread = Thread[pool-1-thread-3,5,main]
CachedThreadPool >> running 3, Thread = Thread[pool-1-thread-4,5,main]
CachedThreadPool >> running 4, Thread = Thread[pool-1-thread-5,5,main]
CachedThreadPool >> running 5, Thread = Thread[pool-1-thread-6,5,main]
CachedThreadPool >> running 6, Thread = Thread[pool-1-thread-7,5,main]
CachedThreadPool >> running 7, Thread = Thread[pool-1-thread-8,5,main]
CachedThreadPool >> running 8, Thread = Thread[pool-1-thread-9,5,main]
CachedThreadPool >> running 9, Thread = Thread[pool-1-thread-10,5,main]

每次执行的Thread信息都不一样,说明每执行一次都创建了一个新的线程。

2、FixedThreadPool
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
定长线程池的大小最好根据系统资源进行设置。

private void fixedThreadPool() {
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            final int index = i;
            fixedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("FixedThreadPool >> running " + index + ", Thread = " + Thread.currentThread().toString());
                    try {
                        Thread.sleep(1000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

打印结果:

FixedThreadPool >> running 0, Thread = Thread[pool-1-thread-1,5,main]
FixedThreadPool >> running 1, Thread = Thread[pool-1-thread-2,5,main]
FixedThreadPool >> running 2, Thread = Thread[pool-1-thread-3,5,main]
FixedThreadPool >> running 3, Thread = Thread[pool-1-thread-4,5,main]
FixedThreadPool >> running 4, Thread = Thread[pool-1-thread-5,5,main]
FixedThreadPool >> running 5, Thread = Thread[pool-1-thread-4,5,main]
FixedThreadPool >> running 6, Thread = Thread[pool-1-thread-3,5,main]
FixedThreadPool >> running 9, Thread = Thread[pool-1-thread-2,5,main]
FixedThreadPool >> running 8, Thread = Thread[pool-1-thread-1,5,main]
FixedThreadPool >> running 7, Thread = Thread[pool-1-thread-5,5,main]

从执行的Thread的信息发现不规律,但是根据线程ID发现只有5个线程,也就是说哪个线程空闲哪个线程去执行任务。

3、SingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

private void singleThread() {
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 20; i++) {
            final int index = i;
            singleThreadExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("SingleThreadExecutor >> running " + index + ", Thread = " + Thread.currentThread().toString());
                    try {
                        Thread.sleep(1000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

打印结果:

SingleThreadExecutor >> running 0, Thread = Thread[pool-1-thread-1,5,main]
SingleThreadExecutor >> running 1, Thread = Thread[pool-1-thread-1,5,main]
SingleThreadExecutor >> running 2, Thread = Thread[pool-1-thread-1,5,main]
SingleThreadExecutor >> running 3, Thread = Thread[pool-1-thread-1,5,main]
SingleThreadExecutor >> running 4, Thread = Thread[pool-1-thread-1,5,main]
SingleThreadExecutor >> running 5, Thread = Thread[pool-1-thread-1,5,main]
SingleThreadExecutor >> running 6, Thread = Thread[pool-1-thread-1,5,main]
SingleThreadExecutor >> running 7, Thread = Thread[pool-1-thread-1,5,main]
SingleThreadExecutor >> running 8, Thread = Thread[pool-1-thread-1,5,main]
SingleThreadExecutor >> running 9, Thread = Thread[pool-1-thread-1,5,main]

从执行的Thread信息发现ID都是同一个,此线程池中只有一个线程,任务是按顺序执行的。

4、ScheduleThreadPool
创建一个定长线程池,支持定时及周期性任务执行。

它有4个可调用方法:

// 1、延迟执行一个Runnable接口的实现
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);

// 2、延迟执行一个Callable接口的实现
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit);

// 3、延迟之后以固定频率执行一个Runnable接口的实现
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);

// 4、延迟之后开始执行一个Runnable接口的实现,之后的每次任务都是在前一个任务结束后延迟delay再执行
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);

/*
3和4的区别:
3是不考虑每个任务的耗时,4要考虑每个任务的耗时,画一个时间轴来理解:

比如 scheduleAtFixedRate(runnable, 1000, 1000, TimeUnit.MILLISECONDS)
和	scheduleWithFixedDelay(runnable, 1000, 1000, scheduleWithFixedDelay)
假如每个任务耗时1秒,两者执行的时间轴(每个_代表1秒,|表示执行任务):
3: _|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|...
4: _|_ _|_ _|_ _|_ _|_ _|_ _|_ _|_ _|...

/

例子:

private void scheduledThreadPool() {
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
//        scheduledThreadPool.scheduleWithFixedDelay(new Runnable() {
        scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println(new Date().toString() + "<< ScheduledThreadPool >> running " + index + ", Thread = " + Thread.currentThread().toString());
                index++;
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, 1000, 1000, TimeUnit.MILLISECONDS);
    }

方法3打印结果:

Thu Nov 05 15:59:17 CST 2020<< ScheduledThreadPool >> start
Thu Nov 05 15:59:18 CST 2020<< ScheduledThreadPool >> running 0, Thread = Thread[pool-1-thread-1,5,main]
Thu Nov 05 15:59:19 CST 2020<< ScheduledThreadPool >> running 1, Thread = Thread[pool-1-thread-1,5,main]
Thu Nov 05 15:59:20 CST 2020<< ScheduledThreadPool >> running 2, Thread = Thread[pool-1-thread-2,5,main]
Thu Nov 05 15:59:21 CST 2020<< ScheduledThreadPool >> running 3, Thread = Thread[pool-1-thread-1,5,main]
Thu Nov 05 15:59:22 CST 2020<< ScheduledThreadPool >> running 4, Thread = Thread[pool-1-thread-3,5,main]
Thu Nov 05 15:59:23 CST 2020<< ScheduledThreadPool >> running 5, Thread = Thread[pool-1-thread-3,5,main]
Thu Nov 05 15:59:24 CST 2020<< ScheduledThreadPool >> running 6, Thread = Thread[pool-1-thread-3,5,main]
Thu Nov 05 15:59:25 CST 2020<< ScheduledThreadPool >> running 7, Thread = Thread[pool-1-thread-3,5,main]
Thu Nov 05 15:59:26 CST 2020<< ScheduledThreadPool >> running 8, Thread = Thread[pool-1-thread-3,5,main]
Thu Nov 05 15:59:27 CST 2020<< ScheduledThreadPool >> running 9, Thread = Thread[pool-1-thread-3,5,main]

从开始到之后的每次延迟任务间隔都是1秒;

方法4打印结果:

Thu Nov 05 16:00:55 CST 2020<< ScheduledThreadPool >> start
Thu Nov 05 16:00:56 CST 2020<< ScheduledThreadPool >> running 0, Thread = Thread[pool-1-thread-1,5,main]
Thu Nov 05 16:00:58 CST 2020<< ScheduledThreadPool >> running 1, Thread = Thread[pool-1-thread-1,5,main]
Thu Nov 05 16:01:00 CST 2020<< ScheduledThreadPool >> running 2, Thread = Thread[pool-1-thread-2,5,main]
Thu Nov 05 16:01:02 CST 2020<< ScheduledThreadPool >> running 3, Thread = Thread[pool-1-thread-1,5,main]
Thu Nov 05 16:01:04 CST 2020<< ScheduledThreadPool >> running 4, Thread = Thread[pool-1-thread-3,5,main]
Thu Nov 05 16:01:06 CST 2020<< ScheduledThreadPool >> running 5, Thread = Thread[pool-1-thread-3,5,main]
Thu Nov 05 16:01:08 CST 2020<< ScheduledThreadPool >> running 6, Thread = Thread[pool-1-thread-3,5,main]
Thu Nov 05 16:01:10 CST 2020<< ScheduledThreadPool >> running 7, Thread = Thread[pool-1-thread-3,5,main]
Thu Nov 05 16:01:12 CST 2020<< ScheduledThreadPool >> running 8, Thread = Thread[pool-1-thread-3,5,main]
Thu Nov 05 16:01:14 CST 2020<< ScheduledThreadPool >> running 9, Thread = Thread[pool-1-thread-3,5,main]

第一个任务是延迟1秒执行的,从第二个开始都是延迟2秒,这2秒是前一个任务执行耗时1秒,然后再延迟1秒执行下一个任务,所以从第二个任务开始都是延迟延迟2秒再执行。

根据上面打印规律可以发现执行任务的线程ID没有没有规律,它是个定长的线程池,有任务时,哪个线程空闲哪个线程来执行任务。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值