JUC–线程创建


JUC–线程创建


线程创建有几种方式?你都会用吗?

方式一 通过继承Thread

class  ExtendThread extends Thread{
    @Override
    public void run() {

            System.out.println(Thread.currentThread().getName()+"ti****** t");

    }
}
    public static void main(String[] args) {
        for(int i=0;i<3;i++){
            new Thread(()->{
                new ExtendThread().run();
            },String.valueOf(i)).start();
        }
 }

方式二 通过实现Runnable

class ExtendRunable implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"ti****** t");
    }
}

    public static void main(String[] args) {
        for(int i=0;i<3;i++){
            new Thread(()->{
                new ExtendRunable().run();
            },String.valueOf(i)).start();
        }
 }

方式三、四 通过实现Callable,使用线程池创建

与前两种相比,有返回值,并且可以异步延迟获取,需要借助futureTask

class ExtendCallable implements Callable<Integer>{

    public ExtendCallable(){
        System.out.println("生成子线程计算任务:t"+Thread.currentThread().getName());
    }

    @Override
    public Integer call() throws Exception {
        System.out.println("执行计算******start********");
        for (int i = 0; i < 100; i++) {
        }
        //每次计算延迟5秒
        try {
            TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}
        System.out.println("执行计算******end********");
        return 100;
    }
}

    public static void main(String[] args) {
        //需要FutureTask的支持 用于接收运算结果 也可以用用于闭锁
        /**
         * 1、多个并行任务同时计算,统计汇总结果
         */

        // 建立任务集合
        List<FutureTask<Integer>> taskList = new ArrayList<FutureTask<Integer>>();
        // 建立线程池
        ExecutorService exec = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            // 传入Callable对象建立FutureTask对象
            FutureTask<Integer> ft = new FutureTask<Integer>(new ExtendCallable());
            taskList.add(ft);
            // 提交给线程池执行任务,也能够经过exec.invokeAll(taskList)一次性提交全部任务;
            exec.submit(ft);
        }
        System.out.println("全部计算任务提交完毕, 主线程接着干其余事情!");

        // 开始统计各计算线程计算结果
        Integer totalResult = 0;
        for (FutureTask<Integer> ft : taskList) {
            try {
                //FutureTask的get方法会自动阻塞,直到获取计算结果为止
                totalResult = totalResult + ft.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        // 关闭线程池
        exec.shutdown();
        System.out.println("多任务计算后的总结果是:" + totalResult);
 }

  • FutureTask可用于异步获取执行结果或取消执行任务的场景。
  • 经过传入Runnable或者Callable的任务给FutureTask,
  • 直接调用其run方法或者放入线程池执行,
  • 以后能够在外部经过FutureTask的get方法异步获取执行结果,所以,
  • FutureTask很是适合用于耗时的计算,主线程能够在完成本身的任务后,
  • 再去获取结果。另外,FutureTask还能够确保即便调用了屡次run方法,
  • 它都只会执行一次Runnable或者Callable任务,或者经过cancel取消FutureTask的执行等

一般两种常见的使用场景,以上是第一种,多个并行任务同时计算,统计汇总结果

以下是第二种,用于高并发下保证只运行一次的情况

保证在高并发时,只创建一次连接。为了方便测试,只是做了模拟

public static void main(String[] args) {
        /**
         * 2、保证高并发情况下,某些任务只执行一次
         * 传统的我们可以通过加锁的方式进行,这里我们采用futureTask
         */

        FuntureTaskDemo funtureTaskDemo = new FuntureTaskDemo();
        for(int i=0;i<10;i++){
            new Thread(()->{
                try {
                    System.out.println(Thread.currentThread().getName()+"t"+funtureTaskDemo.getConnection("mm"));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();
        }
 }

class InnerConnection{
    public InnerConnection(String url) {
        this.url = url;
    }

    private String url;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}
class FuntureTaskDemo{
    private ConcurrentHashMap<String, FutureTask<InnerConnection>> connectionPool = new ConcurrentHashMap<String, FutureTask<InnerConnection>>();

    public InnerConnection getConnection(String key) throws Exception {
        FutureTask<InnerConnection> connectionTask = connectionPool.get(key);
        if (connectionTask != null) {
            return connectionTask.get();
        } else {
            Callable<InnerConnection> callable = new Callable<InnerConnection>() {
                @Override
                public InnerConnection call() throws Exception {
                    // TODO Auto-generated method stub
                    return createConnection();
                }
            };
            FutureTask<InnerConnection> newTask = new FutureTask<InnerConnection>(callable);
            connectionTask = connectionPool.putIfAbsent(key, newTask);
            if (connectionTask == null) {
                connectionTask = newTask;
                connectionTask.run();
            }
            return connectionTask.get();
        }
    }

    //建立Connection
    private InnerConnection createConnection() {
        System.out.println("阻塞中************");
        try {TimeUnit.SECONDS.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
        System.out.println("阻塞结束************");
        return new InnerConnection("9999");
    }
}


原文始发于微信公众号(云户):JUC–线程创建

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/35338.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!