java: chạy một hàm sau một số giây cụ thể


148

Tôi có một chức năng cụ thể mà tôi muốn được thực hiện sau 5 giây. Làm thế nào tôi có thể làm điều đó trong Java?

Tôi đã tìm thấy javax.swing.timer, nhưng tôi thực sự không thể hiểu cách sử dụng nó. Có vẻ như tôi đang tìm kiếm một cái gì đó đơn giản hơn thì lớp này cung cấp.

Vui lòng thêm một ví dụ sử dụng đơn giản.


Bạn có muốn đợi 5 giây và sau đó thực hiện một cái gì đó hoặc bạn muốn tiếp tục làm một cái gì đó khác trong 5 giây?
whiskeyierra

tôi muốn tiếp tục làm một cái gì đó khác
ufk

Câu trả lời:


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

BIÊN TẬP:

javadoc nói:

Sau khi tham chiếu trực tiếp cuối cùng đến một đối tượng Timer biến mất và tất cả các tác vụ chưa hoàn thành đã thực hiện xong, luồng thực thi tác vụ của bộ đếm thời gian kết thúc một cách duyên dáng (và trở thành đối tượng thu gom rác). Tuy nhiên, điều này có thể mất thời gian tùy ý để xảy ra.


1
Nếu bạn chạy mã đó, bạn sẽ rò rỉ chủ đề. Đảm bảo dọn dẹp bộ đếm thời gian khi bạn hoàn thành.
skaffman

1
@skaffman: Tôi đã thêm một tuyên bố từ javadoc. Bạn có thực sự phải dọn dẹp sau khi gọi lịch trình?
tangens

1
Nó có thể ổn, nhưng sau đó có thể không. Nếu bạn chạy đoạn mã đó nhiều lần, bạn sẽ có các luồng lỏng lẻo mà không có cách nào dọn dẹp chúng.
skaffman

5
import java.util.Timer; import java.util.TimerTask;có thể làm cho nó rõ ràng hơn rằng điều này là không javax.swing.Timer. / Lưu ý, nếu bạn đang sử dụng Xoay (và thực tế là AWT), bạn không nên làm bất cứ điều gì để thay đổi các thành phần trên các luồng không xử lý sự kiện (EDT) (EDT)java.util.Timer tác vụ xấu; javax.swing.Timerhành động tốt).
Tom Hawtin - tackline

2
@PaulAlexander Theo tài liệu - cancelphương thức gọi bộ đếm thời gian ở cuối phương thức chạy sẽ xóa luồng xử lý của TimerT Nhiệm vụ.
Dandalf

58

Một cái gì đó như thế này:

// 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();

Có nhiều phương pháp nhà máy khác Executormà bạn có thể sử dụng thay thế, nếu bạn muốn có nhiều chủ đề hơn trong nhóm.

Và hãy nhớ, điều quan trọng là tắt máy của người thực thi khi bạn hoàn thành. Các shutdown()phương pháp sạch sẽ đóng cửa các hồ bơi thread khi nhiệm vụ cuối cùng đã hoàn thành, và sẽ chặn cho đến khi điều này xảy ra. shutdownNow()sẽ chấm dứt nhóm chủ đề ngay lập tức.


24

Ví dụ về việc sử dụng 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!

Mã này sẽ chỉ được thực thi một lần và việc thực thi xảy ra trong 3000 ms (3 giây).

Như camickr đề cập, bạn nên tra cứu " Cách sử dụng bộ đếm thời gian xoay " để giới thiệu ngắn.


6

Mã của tôi là như sau:

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

Là một biến thể của câu trả lời @tangens: nếu bạn không thể đợi trình thu gom rác dọn sạch luồng của mình, hãy hủy bộ hẹn giờ ở cuối phương thức chạy.

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 
);

Không nên Timer tkhai báo finalvì nó được truy cập bên trong một lớp bên trong?
Joshua Pinter

1
@JoshuaPinter Có, nó phải được tuyên bố là cuối cùng nhưng không cần phải tuyên bố rõ ràng cuối cùng trong ít nhất Java 8. Nó chỉ cần là "cuối cùng có hiệu quả" ( javarevisited.blogspot.com/2015/03/ .)
Dandalf

4

Câu hỏi ban đầu của bạn đề cập đến "Bộ đếm thời gian xoay". Nếu trên thực tế, câu hỏi của bạn có liên quan đến SWing, thì bạn nên sử dụng Bộ đếm thời gian xoay và KHÔNG phải là ứng dụng.

Đọc phần từ hướng dẫn Xoay về " Cách sử dụng bộ hẹn giờ " để biết thêm thông tin.


4

bạn có thể sử dụng hàm Thread.S ngủ ()

Thread.sleep(4000);
myfunction();

Chức năng của bạn sẽ thực thi sau 4 giây. Tuy nhiên, điều này có thể tạm dừng toàn bộ chương trình ...


Và nó chỉ đảm bảo rằng việc thực thi sẽ chạy sau 4 giây, có nghĩa là sau 10 giây nữa!
Questzen

2
Questzen, bạn sẽ thấy rằng tất cả các phương pháp ở đây làm điều đó. Trên thực tế, ngay cả khi bạn lên lịch một cái gì đó ở cấp độ HĐH, bạn thường chỉ có thể đảm bảo thời gian trôi qua tối thiểu trước một sự kiện.
Ethan

Đây không phải là câu hỏi thực tế là gì
Inder R Singh

Tôi chỉ phải đưa ra một downvote - hoàn toàn không phải là một câu trả lời cho câu hỏi trong tay.
Người chơi

OP nói trong một bình luận "tôi muốn tiếp tục làm việc khác"; mã này rõ ràng, không.
Abhijit Sarkar

3

ScheduledThreadPoolExecutor có khả năng này, nhưng nó khá nặng.

Timer cũng có khả năng này nhưng mở một số luồng ngay cả khi chỉ được sử dụng một lần.

Đây là một cách thực hiện đơn giản với một bài kiểm tra (chữ ký gần với Handler.postDelayed ()) của Android :

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();
    }
}

Kiểm tra:

@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());
}

nó đưa ra cảnh báo về giấc ngủ được gọi trong một vòng lặp
shareef 21/2/2017

Chỉ whilelà để bỏ qua sự gián đoạn.
AlikElzin-kilaka

2

Tất cả các thông báo khác yêu cầu chạy mã của bạn trong một luồng mới. Trong một số trường hợp sử dụng đơn giản, bạn có thể chỉ muốn đợi một chút và tiếp tục thực hiện trong cùng một luồng / luồng.

Mã dưới đây chứng minh rằng kỹ thuật. Hãy nhớ rằng điều này tương tự như những gì java.util.Timer thực hiện dưới mui xe nhưng nhẹ hơn.

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 Thực hiện

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
Mặc dù mã này có thể trả lời câu hỏi, cung cấp ngữ cảnh bổ sung về lý do và / hoặc cách mã này trả lời câu hỏi cải thiện giá trị lâu dài của nó.
Mateus
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.