• Java并发编程原理与实战五:创建线程的多种方式


    一、继承Thread类

    public class Demo1 extends Thread {
        
        public Demo1(String name) {
            super(name);
        }
        
        @Override
        public void run() {
            while(!interrupted()) {
                System.out.println(getName() + "线程执行了 .. ");
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        
        public static void main(String[] args) {
            
            Demo1 d1 = new Demo1("first-thread");
            Demo1 d2 = new Demo1("second-thread");
            
            
            d1.start();
            d2.start();
            
    //        d1.stop();
            d1.interrupt();
        }
        
    }

    二、实现Runnable 接口

    /**
     * 作为线程任务存在
     * 
     * @author worker
     *
     */
    public class Demo2 implements Runnable {
    
        @Override
        public void run() {
            while(true) {
                System.out.println("thread running ...");
            }
        }
    
        public static void main(String[] args) {
            Thread thread = new Thread(new Demo2());
            thread.start();
        }
        
    }

    三、匿名内部类的方式

    public class Demo3 {
        
        public static void main(String[] args) {
            
            /*new Thread() {
                public void run() {
                    System.out.println("thread start ..");
                };
            }.start();*/
            
            
            /*new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("thread start ..");
                }
            }).start();*/
            
            
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("runnable");
                }
            }) {
                public void run() {
                    System.out.println("sub");
                };
            }.start();
            
            
        }
    
    }

    四、带返回值的线程

    import java.util.concurrent.Callable;
    import java.util.concurrent.FutureTask;
    
    public class Demo4 implements Callable<Integer> {
        
        
        public static void main(String[] args) throws Exception {
            Demo4 d = new Demo4();
            
            FutureTask<Integer> task = new FutureTask<>(d);
            
            Thread t = new Thread(task);
            
            t.start();
            
            System.out.println("我先干点别的。。。");
            
            Integer result = task.get();
            System.out.println("线程执行的结果为:" + result);
        }
    
        @Override
        public Integer call() throws Exception {
            System.out.println("正在进行紧张的计算....");
            Thread.sleep(3000);
            return 1;
        }
    
    }

    五、定时器

    import java.util.Timer;
    import java.util.TimerTask;
    
    public class Demo5 {
    
        public static void main(String[] args) {
    
            Timer timer = new Timer();
    
            timer.schedule(new TimerTask() {
    
                @Override
                public void run() {
                    // 实现定时任务
                    System.out.println("timertask is run");
                }
            }, 0, 1000);
    
        }
    
    }

    六、线程池的实现

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class Demo6 {
    
        public static void main(String[] args) {
    
            ExecutorService threadPool = Executors.newCachedThreadPool();
    
            for (int i = 0; i < 1000; i++) {
                threadPool.execute(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(Thread.currentThread().getName());
                    }
                });
            }
            
            threadPool.shutdown();
        }
    
    }

    七、Lambda表达式实现

    import java.util.Arrays;
    import java.util.List;
    
    public class Demo7 {
        
        public static void main(String[] args) {
            
            List<Integer> values = Arrays.asList(10,20,30,40);
            int res = new Demo7().add(values);
            System.out.println("计算的结果为:" + res);
            
            
        }
        
        
        
        public int add (List<Integer> values) {
    //        values.parallelStream().forEach(System.out :: println);
            return values.parallelStream().mapToInt( i -> i * 2).sum();
        }
    
    }

    八、Spring实现多线程

    spring通过任务执行器TaskExecutor来实现多线程与并发编程。通常使用ThreadPoolTaskExecutor来实现一个基于线程池的TaskExecutor.

    首先你要实现AsyncConfigurer 这个接口,目的是开启一个线程池.

    import java.util.concurrent.Executor;
    
    import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.annotation.AsyncConfigurer;
    import org.springframework.scheduling.annotation.EnableAsync;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
    
    /**
     * 注入一个线程池
     * @author mingge
     *
     */
    
    @Configuration
    @ComponentScan("com.foreveross.service.weixin.test.thread")
    @EnableAsync
    public class TaskExecutorConfig implements AsyncConfigurer {
    
        @Override
        public Executor getAsyncExecutor() {
            ThreadPoolTaskExecutor taskExecutor=new ThreadPoolTaskExecutor();
            taskExecutor.setCorePoolSize(5);
            taskExecutor.setMaxPoolSize(20);
            taskExecutor.setQueueCapacity(25);
            taskExecutor.initialize();
            return taskExecutor;
        }
    
        @Override
        public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
            return null;
        }
    
        
    }

    然后注入一个类,实现你的业务,并在你的Bean的方法中使用@Async注解来声明其是一个异步任务

    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Service;
    
    /**
     * 线程池任务
     * @author mingge
     *
     */
    @Service
    public class TaskService {
    
        @Async
        public void executeAsyncTask(int i){
            System.out.println("执行异步任务:"+i);
        }
        
        @Async
        public void executeAsyncTask1(int i){
            System.out.println("执行异步任务1:"+(i+i));
        }
    }

    最后通过测试,可以看到你的实现是异步执行了.

    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    
    /**
     * 
     * @author mingge
     *
     */
    public class Test {
    
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(TaskExecutorConfig.class);
            TaskService taskService=context.getBean(TaskService.class);
            for(int i=0;i<20;i++){
                taskService.executeAsyncTask(i);
                taskService.executeAsyncTask1(i);
            }
            //最后可以根据结果可以看出结果是并发执行而不是顺序执行的呢
            context.close();
        }
    }

    方式二:XML方式

    spring就提供了ThreadPoolTaskExecutor这个类来实现线程池,线程池是啥,可以理解为数据源,或者有一堆线程的池子也行

    在spring配置中我们可以写好如下代码(大致意思都在注释中,不多说了,百度也一堆):

    <bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
             <!-- 核心线程数 -->
            <property name="corePoolSize" value="5" />
            <!-- 最大线程数 -->
            <property name="maxPoolSize" value="10" />
            <!-- 队列最大长度 >=mainExecutor.maxSize -->
            <property name="queueCapacity" value="25" />
            <!-- 线程池维护线程所允许的空闲时间 -->
            <property name="keepAliveSeconds" value="3000" />
            <!-- 线程池对拒绝任务(无线程可用)的处理策略 ThreadPoolExecutor.CallerRunsPolicy策略 ,调用者的线程会执行该任务,如果执行器已关闭,则丢弃.  -->
            <property name="rejectedExecutionHandler">
                <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
            </property>
        </bean>

    然后定义一个component组件,然后线程的引用就十分简单了,只要把这个线程扔进这个线程池子就行了

    @Component
    public class FileCutter {
        
        @Autowired
        private TaskExecutor taskExecutor;
        
        public void filesMng(String path, String fileName) {
            this.taskExecutor.execute(new CutFilesThread(path,fileName));
        }
        
        private class CutFilesThread implements Runnable {
            private String path;
            private String fileName;
            private CutFilesThread(String path, String fileName) {
                super();
                this.path = path;
                this.fileName = fileName;
            }
            @Override
            public void run() {
                System.out.println("barry... run...");
    //            display(path, fileName);
            }
        }

    最后在你所需要的地方就可以调用这个组件了,不论是service还是controller都行

    @Autowired
        private FileCutter fileCutter;
        
        @RequestMapping("/cut")
        @ResponseBody
        public Object cut(){
            fileCutter.filesMng("your path", "your fileName");
            return "success";
        }

    另外可以参考:https://blog.csdn.net/king_kgh/article/details/76022136

    参考资料:

    龙果学院《Java并发编程原理与实战》

  • 相关阅读:
    C#控件随窗体大小改变而改变
    Java泛型
    php的stristr()函数,查找字符
    java设计模式之桥梁模式(Bridge)
    怎样从本地删除git远程仓库里面的文件
    VS code 修改主题设置代码对其齐线
    vue+webpack安装sass过程中遇到权限不够,直接删除node_modus文件夹重新安装,node_modus先取得管理员权限才能删
    转:git合并冲突解决方法
    git命令行解决冲突文件步骤
    dos常用命令
  • 原文地址:https://www.cnblogs.com/pony1223/p/9349218.html
Copyright © 2020-2023  润新知