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

时间:2023-03-08 15:27:09
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并发编程原理与实战》