刚开始接触java的时候对多线程总是怀抱着好奇心,总想弄明白多线程的好处,为什么要使用多线程编程。甚至于认为使用多线程就比单线程要高大上、要好。但事实真的是这样吗?下面就举一个案列看看
1.使用ThreadPoolExecutor创建线程池(创建线程池有很多种方法,这里就不一一列举了)
/**
* 线程池类
*/
public class CustomThreadPoolExecutor {
private ThreadPoolExecutor pool = null;
/**
* 线程池初始化
*/
public void initialize() {
//ThreadPoolExecutor的构造函数接收4个参数:
//corePoolSize 核心线程池大小
//maximumPoolSize 最大线程池大小
//keepAliveTime 最大存活时间
//unit eepAliveTime时间单位
//workQueue 阻塞队列
pool = new ThreadPoolExecutor(20, 50, 30,
TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(10));
}
/**
* 销毁线程池
*/
public void destroy() {
if(pool!=null) {
pool.shutdown();
}
}
/**
* 获取线程池对象
* @return
*/
public ExecutorService getCustomThreadPoolExecutor() {
return this.pool;
}
}
2. 提供的业务数据类
/**
* 图书类
*/
public class Book implements Comparable<Book>{
private String id; // id
private String name; //书名
private Long sales; //销量
//省略getter,setter 方法
@Override
public int compareTo(Book o) {
Long diff = this.getSales() - o.getSales();
if (diff > 0) {
return 1;
}else if(diff<0) {
return -1;
}
return 0;
}
public class ProvideBooks {
/**
* 获取图书集合
* @return
*/
public static List<Book> getBookList(){
List<Book> bookList = new ArrayList<>();
int l=4000;
for (int i = 0; i < l; i++) {
Random random = new Random();
Book book=new Book();
int sales= random.nextInt(100);
book.setSales(Long.valueOf(sales));
book.setId(UUID.randomUUID().toString().replace("-",""));
book.setName("大江大河");
bookList.add(book);
}
return bookList;
}
}
3. 测试方法1-多线程并发执行
public class Main1 {
public static void main(String[] args) {
Long start=System.currentTimeMillis();
QueryDao queryDao=new QueryDao();
//获取 bookList
List<Book> bookList = ProvideBooks.getBookList();
// 每1000条数据开启一条线程
int threadSize = 1000;
// 总数据条数
int dataSize = bookList.size();
//System.out.println("书籍类别数:"+dataSize);
// 线程数
int threadNum = dataSize / threadSize + 1;
System.out.println("线程数量:" + threadNum);
// 定义标记,过滤threadNum为整数
boolean special = dataSize % threadSize == 0;
// 创建一个线程池
CustomThreadPoolExecutor executor = new CustomThreadPoolExecutor();
executor.initialize();
ExecutorService pool = executor.getCustomThreadPoolExecutor();
// 确定每条线程的数据
List<Book> cutList = null;
// 分割bookList
for (int i = 0; i < threadNum; i++) {
if (i == threadNum - 1) {
if (special) {
break;
}
cutList = bookList.subList(threadSize * i, dataSize);
} else {
cutList = bookList.subList(threadSize * i, threadSize * (i + 1));
}
final List<Book> compareList = cutList;
//(放到线程池中,线程异步执行)
pool.execute(new Runnable() {
@Override
public void run() {
//Collections.sort(compareList);
for (Book book : compareList) {
String sql = "insert into book(id,name,sales) values(?,?,?)";
int result = 0;
synchronized (queryDao){
if (queryDao.getConnection()) {
result = queryDao.executeUpdate(sql, book.getId(), book.getName(), book.getSales());
}
}
if(result>0){
//System.out.println("插入成功");
}
}
}
});
}
executor.destroy();//销毁
while(true){
if(pool.isTerminated()){
System.out.println("所有的子线程都结束了!");
break;
}
}
Long end=System.currentTimeMillis();
System.out.println("总共花费了--"+(end - start)/1000+"."+(end - start) % 1000 +"--s");
}
}
结果如下:
4. 测试方法2-单线程执行
public class Main2 {
public static void main(String[] args) {
Long start = System.currentTimeMillis();
QueryDao queryDao=new QueryDao();
//获取 bookList
List<Book> bookList = ProvideBooks.getBookList();
// 总数据条数
int dataSize = bookList.size();
//System.out.println("书籍类别数:"+dataSize);
int result=0;
for(Book book:bookList){
String sql="insert into book(id,name,sales) values(?,?,?)";
if(queryDao.getConnection()){
result=queryDao.executeUpdate(sql, book.getId(), book.getName(), book.getSales());
}
if(result>0){
//System.out.println("插入成功");
}
}
Long end = System.currentTimeMillis();
System.out.println("总共花费了--" + (end - start) / 1000+"."+(end - start) % 1000 + "--s");
}
}
结果如下:
结果分析
从上述结果中可以看出,多线程下竟然还比单线程慢了0.3秒左右。可见多线程下的效率并不一定比单线程的高。当然跟我的测试数据量也有一定的关系。有兴趣的可以看看《并发编程的艺术》这本书。我这里就不再阐述原因了。