首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 多線程實現數字時鐘:三種經典寫法對比與最佳實踐

     編輯:Java 相關知識

需求分析

構建一個可啟動/停止、獨立運行的數字時鐘,核心需求:

  • 每秒更新時間顯示
  • 支持開始/暫停控制
  • 線程安全,資源正確釋放

方案一:AWT 組件繼承 Runnable(教學經典)

import java.awt.*;
import java.awt.event.*;
import java.util.Date;

class Clock extends Label implements Runnable {
    private Thread clockThread;
    
    public Clock() { setText(new Date().toString()); }
    
    public synchronized void start() {
        if (clockThread == null) {
            clockThread = new Thread(this);
            clockThread.start();
        }
    }
    
    public synchronized void stop() { clockThread = null; }
    
    @Override
    public void run() {
        Thread current = Thread.currentThread();
        while (clockThread == current) { // 線程身份校驗
            setText(new Date().toString());
            try { Thread.sleep(1000); } 
            catch (InterruptedException e) { break; }
        }
    }
}

public class ClockFrame extends Frame implements ActionListener {
    private Button startBtn = new Button("Start");
    private Button stopBtn = new Button("Stop");
    private Clock clock = new Clock();
    
    public ClockFrame() {
        super("數字時鐘");
        setLayout(new FlowLayout());
        add(startBtn); startBtn.addActionListener(this);
        add(stopBtn); stopBtn.addActionListener(this);
        add(clock);
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) { System.exit(0); }
        });
        pack(); setVisible(true);
    }
    
    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == startBtn) clock.start();
        else if (e.getSource() == stopBtn) clock.stop();
    }
    
    public static void main(String[] args) { new ClockFrame(); }
}

優點:邏輯清晰,展示線程生命週期管理;缺點:AWT 組件已過時,Label 不支持豐富樣式。

方案二:Swing + 繼承 JFrame 實現 Runnable(推薦)

import javax.swing.*;
import java.awt.*;
import java.util.Date;

public class TimeDemo extends JFrame implements Runnable {
    private Thread clockThread;
    
    public TimeDemo() {
        super("Swing 數字時鐘");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setFont(new Font("Times New Roman", Font.BOLD, 60));
        setBounds(400, 300, 300, 100);
        setVisible(true);
        startClock();
    }
    
    private synchronized void startClock() {
        if (clockThread == null) {
            clockThread = new Thread(this);
            clockThread.start();
        }
    }
    
    @Override
    public void run() {
        while (clockThread != null) {
            repaint(); // 觸發 paint()
            try { Thread.sleep(1000); } 
            catch (InterruptedException e) { break; }
        }
    }
    
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        Date now = new Date();
        String time = String.format("%tH:%tM:%tS", now, now, now);
        g.setColor(Color.GREEN);
        g.fillRect(0, 0, getWidth(), getHeight());
        g.setColor(Color.RED);
        g.drawString(time, 20, 80);
    }
    
    public static void main(String[] args) { new TimeDemo(); }
}

關鍵點:

  • 覆寫 paint() 自定義繪製,避免標籤組件限制
  • repaint() 異步調度繪製,不阻塞事件線程
  • 設置 EXIT_ON_CLOSE 確保程序正常退出

方案三:Canvas + Calendar 格式化(高精度)

import java.awt.*;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import javax.swing.*;

class ClockCanvas extends Canvas implements Runnable {
    private Thread thread;
    private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
    
    public ClockCanvas() {
        thread = new Thread(this);
        thread.start();
    }
    
    @Override
    public void run() {
        while (true) {
            repaint();
            try { Thread.sleep(1000); } 
            catch (InterruptedException e) { break; }
        }
    }
    
    @Override
    public void paint(Graphics g) {
        g.setFont(new Font("宋體", Font.BOLD, 16));
        g.setColor(Color.ORANGE);
        g.drawString(sdf.format(Calendar.getInstance().getTime()), 45, 25);
    }
}

public class ClockApp {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Canvas 時鐘");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new ClockCanvas());
        frame.setSize(300, 150);
        frame.setVisible(true);
    }
}

優勢:

  • SimpleDateFormat 靈活格式化(含中文單位)
  • Calendar 替代過時的 Date.getHours() 等方法
  • 組件與窗口分離,復用性更強

核心最佳實踐總結

現代化重寫(Java 8+ 推薦)

import javax.swing.*;
import java.awt.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class ModernClock extends JPanel implements Runnable {
    private static final DateTimeFormatter FMT = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
    private volatile boolean running = true;
    private Thread clockThread;
    
    public ModernClock() { setFont(new Font("微軟雅黑", Font.BOLD, 24)); }
    
    public synchronized void start() {
        if (clockThread == null) {
            clockThread = new Thread(this);
            clockThread.start();
        }
    }
    
    public synchronized void stop() {
        running = false;
        clockThread.interrupt();
        clockThread = null;
    }
    
    @Override
    public void run() {
        while (running) {
            repaint();
            try { Thread.sleep(1000); } 
            catch (InterruptedException e) { break; }
        }
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.BLACK);
        g.drawString(LocalDateTime.now().format(FMT), 20, 40);
    }
    
    public static void main(String[] args) {
        JFrame frame = new JFrame("現代數字時鐘");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ModernClock clock = new ModernClock();
        frame.add(clock);
        frame.setSize(400, 100);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        clock.start();
    }
}

掌握多線程時鐘本質是理解 線程生命週期控制、UI 線程與工作線程協作、資源安全釋放 三大核心,可遷移至定時任務、動畫循環等場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
維度建議
UI 框架優先 Swing (JFrame/JPanel),避免 AWT
時間獲取使用 Calendar.getInstance() 或 Java 8 LocalDateTime.now()
格式化DateTimeFormatter (Java 8+) 線程安全,優於 SimpleDateFormat
線程控制volatile 標誌位 + interrupt(),避免直接比較 Thread 引用
繪製方式覆寫 paintComponent(Graphics) (Swing) 而非 paint()
資源釋放窗口關閉時調用 interrupt() 並 join() 等待線程結束