多线程误区:一定会提高效率
2015-04-11 10:49
302 查看
最近在做项目的时候,遇到要对一批大量的数据进行加工处理,于是有人提出了这样一种实现方案:
同时开好几个线程,让这几个线程同时对这批数据进行处理,并认为这样可以提高CPU的利用率,从而提高程序的性能。
其实这样就是对多线程的一个误解,认为多线程一定可以提高系统的发性能,其实不能一概而论。
我们利用多线程做优化的目的是减少IO等待的时间,把一个【纯计算】任务分到多个线程并不会提高CPU的利用率,反而会增加线程间切换的开销。在单核、无IO操作、纯计算的情况下,单线程的执行效率是要比多线程高的,因为线程间来回切换也要一定的开销。但是一般很少系统是只有 计算,而没有IO操作的。所以性能优化的方向应该是对IO操作进行优化,而不是对计算操作进行优化。
Java提供的ArrayBlockingQueue阻塞队列是典型的 生产者 - 消费者 问题的数据结构,利用这个阻塞队列,可以实现读取数据和处理数据两个线程间的并行,减少CPU在IO操作的等待时间,从而提高程序的性能。
为了验证在【纯计算】环境下单线程与多线程的性能差异,我们设计如下测试用例:让一个线程不断对一个数字做减一操作,直到数值减为0,最后统计整个过程花费的时间。在相同的环境下,利用三个线程对这个数据做减一操作,直到数值减为0,计算整个过程花费的时间:
public class Demo1
{
public static void main(String[] args)
{
long startTime = System.currentTimeMillis();
new Test(startTime).start();
}
}
class Test
{
private long startTime;
public Test(long startTime)
{
this.startTime = startTime;
}
int num = 1000000;
Object look = new Object();
public void start()
{
Thread th1 = new Thread(new Runnable()
{
@Override
public void run()
{
calc();
}
}, "Thread1");
Thread th2 = new Thread(new Runnable()
{
@Override
public void run()
{
calc();
}
}, "Thread2");
Thread th3 = new Thread(new Runnable()
{
@Override
public void run()
{
calc();
}
}, "Thread3");
th1.start(); // 只有一个线程在计算
//th2.start();
//th3.start();
}
private void calc()
{
while (true)
{
synchronized (look)
{
if (num > 0)
{
num--;
System.out.println(Thread.currentThread().getName() + " = " + num);
}
else
{
System.out.println(System.currentTimeMillis() - startTime);
break;
}
}
}
}
}
下面分别是在【单线程】、【双线程】和【三线程】的情况下,3次测试的用时(毫秒):
单线程:13295、13233、13334 平均用时:13287.33333333333
双线程:13331、13292、13262 平均用时:13295
三线程:13372、13294、13384 平均用时:13350
分析测试数据不难发现,其实三种情况下差异并不大,因此我们可以得结论:
把一个【纯计算】任务分到多个线程同时执行并不会提高CPU的利用率,反而会增加线程间切换的开销。
同时开好几个线程,让这几个线程同时对这批数据进行处理,并认为这样可以提高CPU的利用率,从而提高程序的性能。
其实这样就是对多线程的一个误解,认为多线程一定可以提高系统的发性能,其实不能一概而论。
我们利用多线程做优化的目的是减少IO等待的时间,把一个【纯计算】任务分到多个线程并不会提高CPU的利用率,反而会增加线程间切换的开销。在单核、无IO操作、纯计算的情况下,单线程的执行效率是要比多线程高的,因为线程间来回切换也要一定的开销。但是一般很少系统是只有 计算,而没有IO操作的。所以性能优化的方向应该是对IO操作进行优化,而不是对计算操作进行优化。
Java提供的ArrayBlockingQueue阻塞队列是典型的 生产者 - 消费者 问题的数据结构,利用这个阻塞队列,可以实现读取数据和处理数据两个线程间的并行,减少CPU在IO操作的等待时间,从而提高程序的性能。
为了验证在【纯计算】环境下单线程与多线程的性能差异,我们设计如下测试用例:让一个线程不断对一个数字做减一操作,直到数值减为0,最后统计整个过程花费的时间。在相同的环境下,利用三个线程对这个数据做减一操作,直到数值减为0,计算整个过程花费的时间:
public class Demo1
{
public static void main(String[] args)
{
long startTime = System.currentTimeMillis();
new Test(startTime).start();
}
}
class Test
{
private long startTime;
public Test(long startTime)
{
this.startTime = startTime;
}
int num = 1000000;
Object look = new Object();
public void start()
{
Thread th1 = new Thread(new Runnable()
{
@Override
public void run()
{
calc();
}
}, "Thread1");
Thread th2 = new Thread(new Runnable()
{
@Override
public void run()
{
calc();
}
}, "Thread2");
Thread th3 = new Thread(new Runnable()
{
@Override
public void run()
{
calc();
}
}, "Thread3");
th1.start(); // 只有一个线程在计算
//th2.start();
//th3.start();
}
private void calc()
{
while (true)
{
synchronized (look)
{
if (num > 0)
{
num--;
System.out.println(Thread.currentThread().getName() + " = " + num);
}
else
{
System.out.println(System.currentTimeMillis() - startTime);
break;
}
}
}
}
}
下面分别是在【单线程】、【双线程】和【三线程】的情况下,3次测试的用时(毫秒):
单线程:13295、13233、13334 平均用时:13287.33333333333
双线程:13331、13292、13262 平均用时:13295
三线程:13372、13294、13384 平均用时:13350
分析测试数据不难发现,其实三种情况下差异并不大,因此我们可以得结论:
把一个【纯计算】任务分到多个线程同时执行并不会提高CPU的利用率,反而会增加线程间切换的开销。
相关文章推荐
- C# 多线程、控制线程数提高循环输出效率
- java多线程(七)提高锁的效率——使用读写锁
- 多线程的效率一定快吗?
- 多线程为什么可以提高效率
- C# 多线程、控制线程数提高循环输出效率
- lucene-利用内存中索引和多线程提高索引效率
- C# 多线程、控制线程数提高循环输出效率
- 多线程写文件是否提高效率?
- Java利用多线程执行SQL减少执行时间提高效率
- lucene-利用内存中索引和多线程提高索引效率
- C:笔记:++ 和 -- 不一定能提高效率
- 工欲善其事,必先利其器。一个强大的开发环境可以大大提高工作效率。好吧,我知道这是废话。。。不过,我想一定有很多跟我一样打算进入Linux平台开发的新手,一开始都为找不到一个像Windows下的VS那样
- Python 3基础教程41-多线程不一定效率就高
- 关于多线程io能否提高程序效率
- lucene-利用内存中索引和多线程提高索引效率
- 多线程不是为了提高效率,而是不必等待
- 李开复:如何在一定效率下充分地利用时间来提高才华
- 多线程模型真的能够提高效率吗?
- 多线程不是为了提高效率,而是不必等待
- JAVA多线程,真的提高了效率吗?