java: เรียกใช้ฟังก์ชั่นหลังจากจำนวนวินาทีที่เฉพาะเจาะจง


148

ฉันมีฟังก์ชั่นเฉพาะที่ฉันต้องการถูกเรียกใช้หลังจาก 5 วินาที ฉันจะทำสิ่งนั้นใน Java ได้อย่างไร

ฉันพบ javax.swing.timer แต่ฉันไม่เข้าใจวิธีการใช้งาน ดูเหมือนว่าฉันกำลังมองหาบางสิ่งที่ง่ายขึ้นแล้วคลาสนี้ก็จัดให้

โปรดเพิ่มตัวอย่างการใช้งานแบบง่าย


คุณต้องการที่จะรอ 5 วินาทีแล้วดำเนินการบางอย่างหรือคุณต้องการที่จะทำอย่างอื่นต่อไปใน 5 วินาที?
whiskinssierra

ฉันต้องการที่จะทำอย่างอื่นต่อไป
ufk

คำตอบ:


229
new java.util.Timer().schedule( 
        new java.util.TimerTask() {
            @Override
            public void run() {
                // your code here
            }
        }, 
        5000 
);

แก้ไข:

javadocพูดว่า:

หลังจากการอ้างอิงสดครั้งสุดท้ายไปยังวัตถุตัวจับเวลาและการทำงานที่ค้างอยู่ทั้งหมดได้ดำเนินการเสร็จสิ้นแล้วเธรดการดำเนินงานของตัวจับเวลาจะสิ้นสุดลงอย่างสวยงาม (และอาจมีการรวบรวมขยะ) อย่างไรก็ตามการทำเช่นนี้อาจใช้เวลานานกว่าจะเกิดขึ้นโดยพลการ


1
หากคุณเรียกใช้รหัสนั้นคุณจะรั่วไหลหัวข้อ ตรวจสอบให้แน่ใจว่าได้ล้างตัวจับเวลาเมื่อเสร็จสิ้น
skaffman

1
@skaffman: ฉันได้เพิ่มคำสั่งจาก javadoc คุณต้องล้างข้อมูลหลังจากกำหนดการโทรหรือไม่
tangens

1
มันอาจจะโอเค แต่ก็อาจจะไม่เป็นเช่นนั้น หากคุณเรียกใช้ชิ้นส่วนของรหัสนั้นหลายครั้งคุณจะมีกระทู้หลวม ๆ ที่ไม่มีการเรียงลำดับ
skaffman

5
import java.util.Timer; import java.util.TimerTask;javax.swing.Timerอาจทำให้มันชัดเจนมากว่านี้ไม่ได้ / หมายเหตุถ้าคุณใช้ Swing (และ AWT จริง ๆ ) คุณไม่ควรทำสิ่งใดเพื่อเปลี่ยนส่วนประกอบในเธรดที่ไม่ใช่เหตุการณ์ Dispatch Thread (EDT) ( java.util.Timerงานไม่ดีjavax.swing.Timerการกระทำที่ดี)
Tom Hawtin - tackline

2
@PaulAlexander ตามเอกสาร - การเรียกใช้ตัวจับเวลาcancelในตอนท้ายของวิธีการเรียกใช้จะล้างเธรดการดำเนินการของ TimerTasks
Dandalf

58

บางสิ่งเช่นนี้

// When your program starts up
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

// then, when you want to schedule a task
Runnable task = ....    
executor.schedule(task, 5, TimeUnit.SECONDS);

// and finally, when your program wants to exit
executor.shutdown();

มีวิธีการอื่นจากโรงงานหลายวิธีExecutorที่คุณสามารถใช้แทนหากคุณต้องการเธรดเพิ่มเติมในพูล

และจำไว้ว่ามันเป็นสิ่งสำคัญที่จะต้องปิดผู้ปฏิบัติการเมื่อคุณทำเสร็จแล้ว shutdown()วิธีการเรียบร้อยจะปิดตัวลงสระว่ายน้ำด้ายเมื่องานที่ผ่านมาได้เสร็จสมบูรณ์และจะป้องกันจนกระทั่งเกิดเหตุการณ์นี้ shutdownNow()จะยกเลิกเธรดพูลทันที


24

ตัวอย่างการใช้งาน javax.swing.Timer

Timer timer = new Timer(3000, new ActionListener() {
  @Override
  public void actionPerformed(ActionEvent arg0) {
    // Code to be executed
  }
});
timer.setRepeats(false); // Only execute once
timer.start(); // Go go go!

รหัสนี้จะถูกดำเนินการเพียงครั้งเดียวและการดำเนินการจะเกิดขึ้นใน 3000 มิลลิวินาที (3 วินาที)

ในฐานะที่เป็น camickr กล่าวถึงคุณควรค้นหา " วิธีการใช้ตัวจับเวลาสวิง " สำหรับการแนะนำสั้น ๆ


6

รหัสของฉันเป็นดังนี้:

new java.util.Timer().schedule(

    new java.util.TimerTask() {
        @Override
        public void run() {
            // your code here, and if you have to refresh UI put this code: 
           runOnUiThread(new   Runnable() {
                  public void run() {
                            //your code

                        }
                   });
        }
    }, 
    5000 
);

5

ในรูปแบบของ @tangens ตอบ: ถ้าคุณไม่สามารถรอให้ตัวรวบรวมขยะล้างเธรดของคุณให้ยกเลิกตัวจับเวลาในตอนท้ายของวิธีการเรียกใช้

Timer t = new java.util.Timer();
t.schedule( 
        new java.util.TimerTask() {
            @Override
            public void run() {
                // your code here
                // close the thread
                t.cancel();
            }
        }, 
        5000 
);

ไม่ควรTimer tประกาศfinalเนื่องจากมีการเข้าถึงภายในชั้นในใช่หรือไม่
Joshua Pinter

1
@JoshuaPinter ใช่มันควรจะประกาศครั้งสุดท้าย แต่ไม่จำเป็นต้องมีการประกาศอย่างชัดเจนในขั้นสุดท้ายใน Java 8 อย่างน้อยมันก็จะต้อง "มีประสิทธิภาพขั้นสุดท้าย" ( javarevisited.blogspot.com/2015/03/ … )
Dandalf

4

คำถามเดิมของคุณพูดถึง "Swing Timer" หากในความเป็นจริงคำถามของคุณเกี่ยวข้องกับ SWing คุณควรใช้ Swing Timer ไม่ใช่ตัวจับเวลา

อ่านหัวข้อจากบทช่วยสอนการแกว่งที่ " วิธีใช้ตัวจับเวลา " สำหรับข้อมูลเพิ่มเติม


4

คุณสามารถใช้ฟังก์ชัน Thread.Sleep ()

Thread.sleep(4000);
myfunction();

ฟังก์ชั่นของคุณจะทำงานหลังจาก 4 วินาที อย่างไรก็ตามสิ่งนี้อาจหยุดโปรแกรมทั้งหมดชั่วคราว ...


และรับประกันได้เพียงว่าการดำเนินการจะทำงานหลังจาก 4sec ซึ่งอาจหมายถึงหลังจาก 10 วินาทีเช่นกัน!
questzen

2
เควสคุณจะพบว่าวิธีการทั้งหมดที่นี่ทำ ในความเป็นจริงแม้ว่าคุณจะกำหนดเวลาบางอย่างในระดับระบบปฏิบัติการ แต่โดยทั่วไปคุณสามารถรับประกันเวลาที่ผ่านไปน้อยที่สุดก่อนเหตุการณ์
อีธาน

นี่ไม่ใช่สิ่งที่เกิดขึ้นจริงคำถาม
Inder R Singh

ฉันเพียงแค่ต้องให้ downvote นี้ - ไม่ใช่คำตอบสำหรับคำถามที่อยู่ในมือ
theMayer

OP กล่าวในความคิดเห็นว่า "ฉันต้องการทำอย่างอื่นต่อไป"; เห็นได้ชัดว่ารหัสนี้ไม่
Abhijit Sarkar

3

ScheduledThreadPoolExecutor มีความสามารถนี้ แต่มันค่อนข้างหนา

Timer ยังมีความสามารถนี้ แต่เปิดหลายเธรดแม้ว่าจะใช้เพียงครั้งเดียว

นี่คือการใช้งานง่าย ๆ ด้วยการทดสอบ (ลายเซ็นใกล้กับ Android's Handler.postDelayed () ):

public class JavaUtil {
    public static void postDelayed(final Runnable runnable, final long delayMillis) {
        final long requested = System.currentTimeMillis();
        new Thread(new Runnable() {
            @Override
            public void run() {
                // The while is just to ignore interruption.
                while (true) {
                    try {
                        long leftToSleep = requested + delayMillis - System.currentTimeMillis();
                        if (leftToSleep > 0) {
                            Thread.sleep(leftToSleep);
                        }
                        break;
                    } catch (InterruptedException ignored) {
                    }
                }
                runnable.run();
            }
        }).start();
    }
}

ทดสอบ:

@Test
public void testRunsOnlyOnce() throws InterruptedException {
    long delay = 100;
    int num = 0;
    final AtomicInteger numAtomic = new AtomicInteger(num);
    JavaUtil.postDelayed(new Runnable() {
        @Override
        public void run() {
            numAtomic.incrementAndGet();
        }
    }, delay);
    Assert.assertEquals(num, numAtomic.get());
    Thread.sleep(delay + 10);
    Assert.assertEquals(num + 1, numAtomic.get());
    Thread.sleep(delay * 2);
    Assert.assertEquals(num + 1, numAtomic.get());
}

มันให้คำเตือนการนอนหลับที่เรียกว่าในวง
shareef

whileเป็นเพียงการละเว้นการหยุดชะงัก
AlikElzin-kilaka

2

คำตอบอื่น ๆ ทั้งหมดจำเป็นต้องเรียกใช้โค้ดของคุณภายในเธรดใหม่ ในกรณีที่ใช้ง่ายคุณอาจต้องรอสักครู่และดำเนินการต่อภายในเธรด / โฟลว์เดียวกัน

รหัสด้านล่างแสดงให้เห็นถึงเทคนิคที่ โปรดทราบว่าสิ่งนี้คล้ายกับสิ่งที่ java.util.Timer ทำภายใต้ประทุน แต่มีน้ำหนักเบากว่า

import java.util.concurrent.TimeUnit;
public class DelaySample {
    public static void main(String[] args) {
       DelayUtil d = new DelayUtil();
       System.out.println("started:"+ new Date());
       d.delay(500);
       System.out.println("half second after:"+ new Date());
       d.delay(1, TimeUnit.MINUTES); 
       System.out.println("1 minute after:"+ new Date());
    }
}

DelayUtil Implementation

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class DelayUtil {
    /** 
    *  Delays the current thread execution. 
    *  The thread loses ownership of any monitors. 
    *  Quits immediately if the thread is interrupted
    *  
    * @param duration the time duration in milliseconds
    */
   public void delay(final long durationInMillis) {
      delay(durationInMillis, TimeUnit.MILLISECONDS);
   }

   /** 
    * @param duration the time duration in the given {@code sourceUnit}
    * @param unit
    */
    public void delay(final long duration, final TimeUnit unit) {
        long currentTime = System.currentTimeMillis();
        long deadline = currentTime+unit.toMillis(duration);
        ReentrantLock lock = new ReentrantLock();
        Condition waitCondition = lock.newCondition();

        while ((deadline-currentTime)>0) {
            try {
                lock.lockInterruptibly();    
                waitCondition.await(deadline-currentTime, TimeUnit.MILLISECONDS);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            } finally {
                lock.unlock();
            }
            currentTime = System.currentTimeMillis();
        }
    }
}

2
public static Timer t;

public synchronized void startPollingTimer() {
        if (t == null) {
            TimerTask task = new TimerTask() {
                @Override
                public void run() {
                   //Do your work
                }
            };

            t = new Timer();
            t.scheduleAtFixedRate(task, 0, 1000);
        }
    }

2
ในขณะที่รหัสนี้อาจตอบคำถาม แต่มีบริบทเพิ่มเติมเกี่ยวกับสาเหตุและ / หรือวิธีการที่รหัสนี้ตอบคำถามช่วยปรับปรุงมูลค่าระยะยาว
Mateus
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.