Java实现多线程的方式有几种:
1.继承Thread类,重写run()方法,通过start()方法运行run()方法;
2.实现Runnable接口,同样是重写run()方法;
3.实现Callable接口通过FutureTask包装器来创建Thread线程;
4.线程池。
我这里是实现Runnable接口来创建多线程:
import com.example.demo.dao.TeacherDao;
import com.example.demo.model.entity.TeacherEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
public class ThreadForTeacher implements Runnable {
private final Logger logger = LoggerFactory.getLogger(ThreadForTeacher.class);
private CountDownLatch countDownLatch;
private TeacherDao teacherDao;
public ConcurrentHashMap> classMap = new ConcurrentHashMap<>();
@Override
public void run() {
logger.info("-------------查询教师信息-------------");
try {
ListteacherList = teacherDao.queryTeacherList();
classMap.put("teacherList", teacherList);
} finally {
// 防止线程执行时出现异常
countDownLatch.countDown();
}
}
public ThreadForTeacher(CountDownLatch countDownLatch, TeacherDao teacherDao) {
this.countDownLatch = countDownLatch;
this.teacherDao = teacherDao;
}
}
看代码,我这里用到了CountDownLatch,下面我们再来说说CountDownLatch的作用:
1.简单的说,CountDownLatch就是一个计数器,常用的两个方法分别是:
countDown() 计数减一
await() 等待所有线程计数到0时,并行执行,也就是等待所有线程创建完成后同时执行
使用场景:当我们需要拿到所有线程返回的结果并对数据进行组装(需要返回值,我们可以实现Callable接口,当线程执行完后可以获取一个Future对象,通过get()方法拿到返回结果,我这里偷个懒直接用Runnable实现);
上面只贴出了创建Teacher的线程,Student和Classes同上,只是Entity和Dao的不同;
那么在service层我们是怎么去调用的呢,而且上面teacherDao我并没有加@Atuowried注解,说明teacherDao是Null,再看看上面我们的构造函数,我们在创建ThreadForTeacher对象把teacherDao传过来,这样teacherDao就不再是Null;
下面我们一起来看看代码:
import com.alibaba.fastjson.JSON;
import com.example.demo.dao.ClassDao;
import com.example.demo.dao.StudentDao;
import com.example.demo.dao.TeacherDao;
import com.example.demo.model.entity.ClassEntity;
import com.example.demo.model.entity.StudentEntity;
import com.example.demo.model.entity.TeacherEntity;
import com.example.demo.service.ThreadService;
import com.example.demo.thread.ThreadForClass;
import com.example.demo.thread.ThreadForStudent;
import com.example.demo.thread.ThreadForTeacher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Service
public class ThreadServiceImpl implements ThreadService {
private final Logger logger = LoggerFactory.getLogger(ThreadServiceImpl.class);
@Autowired
private ClassDao classDao;
@Autowired
private TeacherDao teacherDao;
@Autowired
private StudentDao studentDao;
@Override
public void queryAll() {
// 这里我创建了三个Thread,所以是new CountDownLatch(3)
CountDownLatch countDownLatch = new CountDownLatch(3);
ThreadForClass threadForClass = new ThreadForClass(countDownLatch, classDao);
ThreadForTeacher threadForTeacher = new ThreadForTeacher(countDownLatch, teacherDao);
ThreadForStudent threadForStudent = new ThreadForStudent(countDownLatch, studentDao);
// 创建线程池,保护线程运行
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 6, 2, TimeUnit.SECONDS, new LinkedBlockingDeque<>(), new ThreadPoolExecutor.DiscardOldestPolicy());
threadPoolExecutor.execute(threadForClass);
threadPoolExecutor.execute(threadForTeacher);
threadPoolExecutor.execute(threadForStudent);
try {
// 等待所有线程执行结束
countDownLatch.await();
} catch (InterruptedException e) {
logger.error("countDownLatch.await执行异常", e);
} finally {
threadPoolExecutor.shutdown();
}
ListclassList = threadForClass.classMap.get("classList");
ListteacherList = threadForTeacher.classMap.get("teacherList");
ListstudentList = threadForStudent.classMap.get("studentList");
System.out.println("班级:" + JSON.toJSONString(classList));
System.out.println("教师:" + JSON.toJSONString(teacherList));
System.out.println("学生:" + JSON.toJSONString(studentList));
}
}
Controller、Dao还有实体类的代码我就不贴出来,非常简单,相信每个人都会,我们运行一下看看是否能打印出我们想要的结果呢?一起来见证!
完全没毛病!
当我们需要去调用多个服务或者查询多表或者大量数据,我们就可以通过多线程编程去实现,提升代码执行效率!