持有锁的线程释放锁的场景
- 加锁的代码块执行完成
- 加锁的代码块执行过程中出现异常线程终止
- Object#wait会释放锁
不会释放锁
- sleep()/join()
- sleep()的目的是让线程暂停指定时间,时间过后线程会继续运行
- join()的目的是让线程等待指定线程执行完成后,它才开可以运行
Thread#interrupt
- 适用与中断处在blocking method状态的线程
- Blocking method包括wait()/join()/sleep()
- 可使用isInterrpted()访问线程中断标识
- 调用Interrupt时可能会抛出InterruptedException异常
- 处理InterruptedException异常时,需要注意重新设置线程中断标记
示例
简单秒表
package org.ybygjy.thread3th.minutes;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
/**
* 秒表主面板
* <p>
* 负责呈现时间
* <p>
* 负责
* @author WangYanCheng
* @version 2012-10-1
*/
public class StopWatch {
/** 用于呈现时间 */
private JTextField timerValue;
/** 时间构建线程 */
private TimeThread timerThread;
/**
* Constructor
*/
public StopWatch() {
this.timerValue = new JTextField("00:18:22 516");
timerThread = new TimeThread(this);
timerThread.start();
}
/**
* 逻辑处理入口
* <p>
* 负责创建JFrame
* <p>
* 负责组织各组件关系
*/
public void doWork() {
JFrame jframe = new JFrame("秒表");
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setContentPane(this.createContentPanel());
jframe.setSize(300, 100);
jframe.setResizable(false);
jframe.setVisible(true);
}
/**
* 主面板,充做组件容器
* @return jPanel {@link JPanel}
*/
private JPanel createContentPanel() {
JPanel jPanel = new JPanel();
jPanel.setLayout(new BorderLayout());
jPanel.add(this.createOpbar(), BorderLayout.NORTH);
jPanel.add(this.timerValue, BorderLayout.CENTER);
return jPanel;
}
/**
* 控制面板,控制按钮的容器
* @return rtnPanel {@link JPanel}
*/
private JPanel createOpbar() {
JPanel rtnPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 5));
final JButton startBtn = new JButton("开始");
final JButton suspendBtn = new JButton("暂停");
rtnPanel.add(startBtn);
rtnPanel.add(suspendBtn);
startBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timerThread.setDone(false);
}
});
suspendBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timerThread.setDone(true);
}
});
return rtnPanel;
}
/**
* 重绘时间
* @param timeValue 时间串
*/
public void repaintTimeValue(final String timeValue) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
timerValue.setText(timeValue);
}
});
}
/**
* 测试入口
* @param args 参数列表
*/
public static void main(String[] args) {
new StopWatch().doWork();
}
}
package org.ybygjy.thread3th.minutes;
import java.text.SimpleDateFormat;
import java.util.Calendar;
/**
* 负责实现秒表时间
* @author WangYanCheng
* @version 2012-10-1
*/
public class TimeThread extends Thread {
/** 暂停标记 */
private boolean isDone;
/** 秒表呈现组件 */
private StopWatch swInst;
/**
* Constructor
* @param swInst {@link StopWatch}
*/
public TimeThread(StopWatch swInst) {
this.swInst = swInst;
// 默认为暂停
this.isDone = true;
}
@Override
public synchronized void run() {
while (true) {
try {
if (isDone) {
wait();
}
// 产生时间串
swInst.repaintTimeValue(getTimeStr());
//sleep(10);
wait(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 暂停标记
* @param isDone {true:暂停;false:继续}
*/
public synchronized void setDone(boolean isDone) {
if (this.isDone == isDone) {
return;
}
this.isDone = isDone;
notify();
}
/**
* 生成时间串
* @return rtnStr 时间串
*/
private String getTimeStr() {
return sdfInst.format(Calendar.getInstance().getTime());
}
/** 时间格式串 */
private static SimpleDateFormat sdfInst = new SimpleDateFormat("HH:mm:ss SS");
}