Java 插入数据库需要零秒时间

Java 插入数据库需要零秒时间,java,database,multithreading,Java,Database,Multithreading,我试图测量数据库插入的性能。为此,我编写了一个StopWatch类,它将在executeUpdate方法之前重置计数器,并计算executeUpdate方法完成后的时间 我试图查看每个线程花费了多少时间,所以我将这些数字保存在ConcurrentHashMap中 下面是我的主课- public static void main(String[] args) { final int noOfThreads = 4; final int noOfTasks = 10

我试图测量
数据库插入的性能。为此,我编写了一个
StopWatch
类,它将在
executeUpdate
方法之前重置计数器,并计算
executeUpdate
方法完成后的时间

我试图查看每个线程花费了多少时间,所以我将这些数字保存在
ConcurrentHashMap

下面是我的主课-

public static void main(String[] args) {

        final int noOfThreads = 4;
        final int noOfTasks = 100;

        final AtomicInteger id = new AtomicInteger(1);

        ExecutorService service = Executors.newFixedThreadPool(noOfThreads);

        for (int i = 0; i < noOfTasks * noOfThreads; i++) {
            service.submit(new Task(id));
        }
        while (!service.isTerminated()) {

        }

           //printing the histogram
          System.out.println(Task.histogram);

    }
运行上述程序后,我可以看到插入了400行。当它打印柱状图时,我看到的只是这样-

{0=400}
也就是说,400个电话在0秒内回复?这不可能确定

我只是想看看每个线程插入记录,然后将这些数字存储在
映射中,然后从主线程打印映射所需的时间。

我认为我假设它发生的问题是因为这里的线程安全性,这就是为什么每当它执行
resetlap
zero时,我猜都会设置为Map

如果是,如何避免此问题?还需要将
直方图映射
从主线程传递到任务的构造函数?因为我需要在所有线程完成后打印该地图,以查看有哪些数字

更新:- 如果我删除
除以1000
的东西来存储毫秒数,那么除了
之外,我还能看到一些数字。看起来不错


但我发现还有一件事,数字是不一致的,如果我每次总结线程,我会得到一些数字。我也在打印整个程序完成的时间。因此,我比较了这两个数字,它们相差很大

为了避免秒表出现并发问题,您最好在
Runnable
run
方法中创建一个新的本地变量。这样每个线程都有自己的秒表

至于你所看到的时间,我绝对希望一个简单的记录插入会在一秒钟内发生。看到400个插页都在不到一秒钟的时间内完成,我一点也不惊讶。使用秒表中的毫秒值作为HashMap键可以获得更好的结果

更新

对于秒表并发问题,我建议如下:

class Task implements Runnable {

    private final AtomicInteger id;
    // Remove the stopwatch from here
    //private StopWatch totalExecTimer = new StopWatch(Task.class.getSimpleName() + ".totalExec");
    public static ConcurrentHashMap<Long, AtomicLong> histogram = new ConcurrentHashMap<Long, AtomicLong>();

    public Task(AtomicInteger id) {
        this.id = id;
    }


    @Override
    public void run() {

        // And add it here
        StopWatch totalExecTimer = new StopWatch(Task.class.getSimpleName() + ".totalExec");

        dbConnection = getDBConnection();
类任务实现可运行{
私有最终原子整数id;
//从这里取下秒表
//私有秒表totalExecTimer=新秒表(Task.class.getSimpleName()+“.totalExec”);
公共静态ConcurrentHashMap直方图=新ConcurrentHashMap();
公共任务(原子整数id){
this.id=id;
}
@凌驾
公开募捐{
//把它加在这里
秒表totalExecTimer=新秒表(Task.class.getSimpleName()+“.totalExec”);
dbConnection=getDBConnection();
通过这种方式,每个线程,实际上每个任务,都有自己的副本,您不必担心并发性。使秒表线程保持现状安全可能比它的价值更麻烦

更新2

话虽如此,您在评论中提到的方法可能会产生更好的结果,因为计时机制的开销更少

要回答您关于累计线程时间和程序总运行时间的差异的问题,我会圆滑地说,“您期望什么?”

这里有两个问题。一个是,您没有测量每个线程的总运行时间,只是测量执行DB插入的位置


另一个是,测量整个应用程序的运行时间并不考虑线程执行时间的任何重叠。即使您测量每个任务的总时间,并假设您在多核机器上运行,我预计累积时间将超过程序执行的时间。这就是并行编程的好处。

出于许多原因,currentTimeMillis在每次调用时都不会“刷新”其值。您应该使用nanoTime进行高分辨率测量

你的代码浪费了几分之一秒。你的toString方法应该使用
sb.append((cumulativeTime/1000.0));
这样你就得到了几分之一秒


但是计时机制的开销是巨大的,如果你真的测量某件事情,那么很大一部分时间将只是计时开销。最好测量多个操作,而不是一个操作。

作为补充说明,System.currentTimeMillis()是伪时间,具有一定程度的不精确性。使用System.nanoTime()是一种更精确的方法

long start = System.nanoTime();

long end = System.nanoTime();

long timeInSeconds = TimeUnit.NANOSECONDS.convert(end-start, TimeUnit.SECONDS);

我明白了。你是说我应该在执行更新方法之前使用这样的
long start\u time=System.currentTimeMillis();
然后这行
long difference=(System.currentTimeMillis()-start\u time)但是,我仍然试图让秒表工作,如果有任何并发问题。并且更新2回答你关于总运行时间的问题:在计时器上存在并发问题。一旦线程在另一个线程试图测量的时间跨度中间重置定时器,就没有什么可以停止了。ks Andrew谢谢你的建议。我实现了大部分。关于你之前的评论,我如何解决计时器上的并发问题?有什么想法吗?就像我说的,我认为这太麻烦了,不值得。你不能使用锁,因为这会真的破坏你的结果。你可能会使用某种信号量来标记t计时器“正在使用”,所以一次只有一个线程可以使用它,但这样你就失去了多线程的任何可能的好处。是的,我会通过运行
class Task implements Runnable {

    private final AtomicInteger id;
    // Remove the stopwatch from here
    //private StopWatch totalExecTimer = new StopWatch(Task.class.getSimpleName() + ".totalExec");
    public static ConcurrentHashMap<Long, AtomicLong> histogram = new ConcurrentHashMap<Long, AtomicLong>();

    public Task(AtomicInteger id) {
        this.id = id;
    }


    @Override
    public void run() {

        // And add it here
        StopWatch totalExecTimer = new StopWatch(Task.class.getSimpleName() + ".totalExec");

        dbConnection = getDBConnection();
long start = System.nanoTime();

long end = System.nanoTime();

long timeInSeconds = TimeUnit.NANOSECONDS.convert(end-start, TimeUnit.SECONDS);