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并发编程原理与实战》

    原文作者:java线程池
    原文地址: https://www.cnblogs.com/pony1223/p/9349218.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞