1.多线程实现方式
- 继承Thread类, 重写run方法,run里面的代码就是我们开启多线程会执行的业务逻辑
/**
* 继承Thread, 重写run方法
*/
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 2000; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
}
}
}
public class Demo {
public static void main(String[] args) {
MyThread myThread = new MyThread();
// start()方法,开辟一个线程内存, 在myThread线程里运行run方法
myThread.start();
for (int i = 0; i < 2000; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
}
}
}
2.实现runable接口, 重写run方法
public class MyRunable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 2000; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
}
}
}
public class Demo {
public static void main(String[] args) {
MyThread myThread = new MyThread();
// start()方法,开辟一个线程内存, 在myThread线程里运行run方法
myThread.start();
for (int i = 0; i < 2000; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
}
MyRunable myRunable = new MyRunable();
Thread thread = new Thread(myRunable,"实现runable");
thread.start();
}
}
3.实现Callable接口, 重写run方法
public class MyCallable implements Callable {
@Override
public List<String> call() throws Exception {
List<String> list =new ArrayList<String>();
for (int i = 0; i < 2000; i++) {
// 往集合里添加2000个元素
list.add("添加"+i);
}
// 执行完2000次,返回个集合
return list;
}
}
public class Demo {
public static void main(String[] args) {
MyThread myThread = new MyThread();
// start()方法,开辟一个线程内存, 在myThread线程里运行run方法
myThread.start();
for (int i = 0; i < 2000; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
}
MyRunable myRunable = new MyRunable();
Thread thread = new Thread(myRunable,"实现runable");
thread.start();
MyCallable myCallable = new MyCallable();
FutureTask<Callable> futureTask = new FutureTask<Callable>(myCallable);
new Thread(futureTask).start();
List result = new ArrayList();
//这边获取callable里返回的数据会有异常,需要捕获
try {
result = (List) futureTask.get();
} catch (Exception e) {
e.printStackTrace();
}
for (Object o : result) {
System.out.println(o);
}
}
}
以上三种是线程的三种基本实现方式
2.利用线程池实现多线程
线程池的实现方式有很多,例如:
1. Executors.newFixedThreadPool(5) 开启固定线程池,分配5个线程
2.CachedThreadPool 可缓存的线程池
3.ScheduledThreadPoolExecutor 支持定时及周期性任务执行
4.ThreadPoolExecutor 可根据实际需要配置的线程池
使用ThreadPoolExecutor批量分段插入100W数据:
public void insertThreadData() {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME,
TimeUnit.SECONDS,
//1. 如果没有空闲的线程执行该任务且当前的线程数等于corePoolSize同时阻塞队列未满,
// 则将任务入队列,而不添加新的线程。
//2. 如果没有空闲的线程执行该任务 且阻塞队列已满同时池中的线程数小于maximumPoolSize,
// 则创建新的线程执行任务。
new ArrayBlockingQueue<>(QUEUE_CAPACITY),
//在任务被拒绝添加后,会在调用execute方法的的线程来执行被拒绝的任务,除非线程被关闭
new ThreadPoolExecutor.CallerRunsPolicy());
List<Long> ids = new ArrayList<>();
for (int i = 1; i <= 1000000; i++) {
String id = idWorker.nextId();
ids.add(Long.parseLong(id));
}
for (int i = 1; i <= 25; i++) {
// 多线程查询, 传入当前页和显示条数, 需要把已经注入的mapper映射传入到run里,这样才不会为null
InsertRunable runable = new InsertRunable(i, threadUserMapper, i * 40000, (i - 1) * 40000, ids);
//提交任务到线程池, submit,不会抛出异常而是把异常保存在成员变量中,在FutureTask.get阻塞获取的时候再把异常抛出来
// executor.submit(runable); 有返回值
// execute直接抛出异常之后线程就死掉了, 没有返回值
executor.execute(runable);
}
//关闭线程池
executor.shutdown();
}
public class InsertRunable implements Runnable {
private int num;
private int endIndex;
private int startIndex;
private ThreadUserMapper threadUserMapper;
private UserService userService;
private List<Long> ids;
public InsertRunable(){
}
// 至少num至少从1开始
public InsertRunable(int num,ThreadUserMapper threadUserMapper, int endIndex, int startIndex, List<Long> ids){
this.endIndex=endIndex;
this.startIndex=startIndex;
this.threadUserMapper = threadUserMapper;
this.userService= new UserService();
this.ids = ids;
this.num = num;
}
@Override
public void run() {
Long startTime = System.currentTimeMillis();
ThreadUser threadUser = new ThreadUser();
for (int i = startIndex; i < endIndex;i++) {
userService.insert(i,threadUserMapper,ids.get(i));
// System.out.println(i);
}
Long endTime = System.currentTimeMillis();
System.out.println("完成第"+num+"次4W数据插入,花费: "+(endTime-startTime)/1000+"s");
}
}
public void insert(int startIndex, ThreadUserMapper userMapper, Long id) {
ThreadUser threadUser = new ThreadUser();
//循环遍历 20W
threadUser.setId(id);
threadUser.setUsername(String.valueOf(startIndex));
threadUser.setPassword(String.valueOf(startIndex));
userMapper.insert(threadUser);
}