一、继承Thread类
public class Demo1 extends Thread {
public Demo1(String name) {
super(name);
}
@Override
public void run() {
//线程正确的结束方式,就是线程执行完毕,线程执行完毕自然就结束了
//终止线程用interrupted(),如果不中断就执行;
//当main()方法调用了interrupt()后,标志改了中断,线程结束
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();
//stop()方法在jdk1.6已经失效,因为线程只是无限期的等待,获取的资源并没有释放
//d1.stop();
//当调用了interrupt()后,标志改了中断,线程结束
d1.interrupt();
}
}
二、实现Runnable接口
//使用Runnable,面向接口编程,使任务和业务分离
//实现Runnable接口的demo2只是一个普通类,作为一个线程任务存在,创建并启用时需要当做参数传入
public class Demo2 implements Runnable {
@Override
public void run() {
while(true) {
System.out.println("thread running ...");
}
}
public static void main(String[] args) {
//Runnable对象作为Thread对象的target,Runnable实现类里面包含run方法仅仅作为执行体。
//也就是说Thread类的作用是把run方法包装成线程的执行体。
//实际运行的线程对象依然是Thread实例,只是该Thread线程负责执行其target的run方法。
Thread thread = new Thread(new Demo2());
//调用start方法,还会调用Thread的run方法,根据源码可知,
//调用了Tread的run方法最后还是调用了调用的Runnable(target)的run方法
thread.start();
}
}
三、实现Callable接口
callable类似于runnable的方式,只有一个方法call(),但是是一个有返回值的方法,这给我们提供了获取方法执行结果的可能,即使它是个异步的任务,它可以获取异常,给我们极大地便利知道任务执行失败的原因。
public class Demo3 implements Callable<Integer> {
public static void main(String[] args) throws Exception {
Demo3 d = new Demo3();
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;
}
}
四、匿名内部类的方式
如果线程我们只需要执行一次,就不需要创建一个类,然后再去创建一个线程了,只需要在代码逻辑中直接重写Thread类中的run方法或者直接重写Runnable类中的run方法即可。
public class Demo4 {
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();*/
}
}
五、线程池
线程池,其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。
public class Demo6 {
public static void main(String[] args) {
//创建一个可缓存的线程池;
//创建线程池有四种方法,分别是:
//newSingleThreadExecutor,单线程线程池
//newFixedThreadPool,固定大小的线程池
//newCachedThreadPool,可缓存的线程池
//newScheduledThreadPool,无限大小的线程池
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();
}
}
六、springboot配置线程池使用多线程
1、配置线程池
//利用EnableAsync来开启Springboot对于异步任务的支持
@Configuration
@EnableAsync
public class ThreadConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(15);
executor.setQueueCapacity(25);
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
}
2、任务执行代码
@Service
public class AsyncTaskService {
//注解@Async表明该方法是异步方法
@Async
public void executeAsyncTask(int i) {
System.out.println("线程" + Thread.currentThread().getName() + " 执行异步任务:" + i);
}
}
3、测试
public class SpringbootLearnApplicationTests {
@Autowired
private AsyncTaskService asyncTaskService;
@Test
public void contextLoads() {
}
@Test
public void threadTest() {
for (int i = 0; i < 20; i++) {
asyncTaskService.executeAsyncTask(i);
}
}
}
七、Lambda表达式实现多线程
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);
//parallelStream()方法是并行执行的,而stream()方法是串行执行的
return values.parallelStream().mapToInt( i -> i * 2).sum();
}
}
如果想要验证parallelStream()是否是并行执行的,可以利用这个方法打印一下list中的元素,如果打印出来的元素是乱序的,那么就是并行执行的。
values.parallelStream().forEach(System.out :: println);
执行后打印出来的结果如下:
values.stream().forEach(System.out :: println);
而执行普通的stream流打印结果如下: