【并发编程】-创建多线程的七种方法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ldb987/article/details/85008294

一、继承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流打印结果如下:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/ldb987/article/details/85008294