Java创建多线程的四种方式
文章目录
一、继承Thread类创建线程
/**
* @author Fox
* @date 2021/12/02 15:17
*/
public class Thread_1 extends Thread {
public void run(){
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread()+"序号为"+i);
}
}
public static void main(String[] args) {
Thread thread1 = new Thread_1();
Thread thread2 = new Thread_1();
Thread thread3 = new Thread_1();
thread1.start();
thread2.start();
thread3.start();
}
}
结果如下图
注意:
继承Thread方式创建线程本质上还是通过实现Runnable接口来完成的
Thread类源码
👇
二、实现Runable接口创建线程
/**
* @author Fox
* @date 2021/12/02 15:30
*/
public class Thread_2 {
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 3; j++) {
System.out.println(Thread.currentThread()+"该线程循环的次数为:"+j);
}
}
}).start();
}
}
}
结果如下图:
三、通过Callable接口创建线程
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* @author Fox
* @date 2021/12/02 16:06
*/
public class Thread_3 {
private static int socunt = 20;
public static void main(String[] args) {
FutureTask ft = new FutureTask(new Callable() {
@Override
public Object call() throws Exception {
for (int i = 1; i <= 20 ; i++) {
socunt--;
System.out.println("当前卖出1,还剩余"+ socunt);
}
return "sale out";
}
});
new Thread(ft).start();
try {
System.out.println(ft.get());
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果如下图:
通过Callable接口创建与通过Runnable接口创建线程的区别:
- 通过Callable实现可以抛出异常,而Runnable实现不会抛出异常.
- 通过Callable实现具有返回值,而Runnable实现没有返回值.
- 通过Callable实现调用的方法是call(),而Runnable实现调用的方法是run().
FutureTask是Runnable接口的实现类,根据对Java多态的理解,父类或接口的引用指向子类或实现类的对象。可知传入一个FutureTask对象就相当于传入了一个Runnable接口的具体实现。
四、通过线程池创建线程
说明:
根据阿里Java开发手册可得知线程资源必须通过线程池提供,不允许在应用中自行显示创建线程
原因是线程池的好处在于减少在创建和销毁线程上所消耗的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者"过度切换"问题。
1、Executors.newFixedThreadPool(int)
/**
* @author Fox
* @date 2021/12/02 18:13
*/
public class newFixedThreadPool {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int i = 0; i < 7; i++) {
executorService.submit(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 3; j++) {
System.out.println("线程池"+Thread.currentThread().getName()+"执行的第"+j+"次");
}
}
},i);
}
executorService.shutdown();
}
}
线程池pool-1-thread-3执行的第0次
线程池pool-1-thread-4执行的第0次
线程池pool-1-thread-1执行的第0次
线程池pool-1-thread-1执行的第1次
线程池pool-1-thread-2执行的第0次
线程池pool-1-thread-1执行的第2次
线程池pool-1-thread-4执行的第1次
线程池pool-1-thread-3执行的第1次
线程池pool-1-thread-1执行的第0次
线程池pool-1-thread-4执行的第2次
线程池pool-1-thread-5执行的第0次
线程池pool-1-thread-5执行的第1次
线程池pool-1-thread-5执行的第2次
线程池pool-1-thread-2执行的第1次
线程池pool-1-thread-4执行的第0次
线程池pool-1-thread-1执行的第1次
线程池pool-1-thread-3执行的第2次
线程池pool-1-thread-1执行的第2次
线程池pool-1-thread-4执行的第1次
线程池pool-1-thread-4执行的第2次
线程池pool-1-thread-2执行的第2次
2、Executors.newSingleThreadPool(int)
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author Fox
* @date 2021/12/02 18:21
*/
public class newSingleThreadPool {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 3; i++) {
executorService.submit(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 3; j++) {
System.out.println("线程池"+Thread.currentThread().getName()+"执行的第"+j+"次");
}
}
},i);
}
executorService.shutdown();
}
}
线程池pool-1-thread-1执行的第0次
线程池pool-1-thread-1执行的第1次
线程池pool-1-thread-1执行的第2次
线程池pool-1-thread-1执行的第0次
线程池pool-1-thread-1执行的第1次
线程池pool-1-thread-1执行的第2次
线程池pool-1-thread-1执行的第0次
线程池pool-1-thread-1执行的第1次
线程池pool-1-thread-1执行的第2次
3、Executors.newCachedThreadPool(int)
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author Fox
* @date 2021/12/02 18:26
*/
public class newCachedThreadPool {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 3; i++) {
executorService.submit(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 3; j++) {
System.out.println("线程池"+Thread.currentThread().getName()+"执行的第"+j+"次");
}
}
},i);
}
executorService.shutdown();
}
}
线程池pool-1-thread-3执行的第0次
线程池pool-1-thread-3执行的第1次
线程池pool-1-thread-3执行的第2次
线程池pool-1-thread-2执行的第0次
线程池pool-1-thread-1执行的第0次
线程池pool-1-thread-1执行的第1次
线程池pool-1-thread-1执行的第2次
线程池pool-1-thread-2执行的第1次
线程池pool-1-thread-2执行的第2次
三种方式底层都是new ThreadPoolExecutor();
4、ThreadPoolExecutor自定义线程池
import java.util.concurrent.*;
/**
* @author Fox
* @date 2021/12/02 18:30
*/
public class ThreadPoolByMyself {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
2,//核心线程池数量
5,//最大线程池
3L,//空闲线程的存活时间
TimeUnit.SECONDS,//空闲线程存活时间单位
new ArrayBlockingQueue<>(3)//阻塞队列个数
);
try{
for (int i = 0; i < 8; i++) {
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" 处理业务");
}
});
}
}finally {
threadPoolExecutor.shutdown();
}
}
}
pool-1-thread-1 处理业务
pool-1-thread-4 处理业务
pool-1-thread-5 处理业务
pool-1-thread-3 处理业务
pool-1-thread-1 处理业务
pool-1-thread-2 处理业务
pool-1-thread-5 处理业务
pool-1-thread-4 处理业务
注意
一般使用自定义线程池来满足业务需求