java期末考试都考完了,实验课却还没完,课程设计也还没开始做,本来打算把最后两次实验尽快做完,然后好好做课设,(我早就想写的坦克大战,过几天写好了,也肯定要整理发布出来)。可却被多线程一题给坑了,题目如下:

编写GUI程序,实现文件的复制功能,要求以进度条实时显示复制进度

复制都很简单,关键进度条实时显示进度,昨晚调到1:40,今天早上7点起来一直调到11:00,才勉强解决,还有一点问题,过几天等老师公布答案再来完善,老师的方案应该比较完善(可惜后来找他要都不给~)

我复制过程中调用System.out.println(progressBar.getValue());控制台都能实时显示当前进度从0~100,但UI界面的进度条就是雷打不动,一直0%懒得我都想踢死它了。。直到复制完成后才突然突变为100%,明显这不是实时显示

百度好几个小时,最终发现“当应用程序在事件线程中执行长时间的操作时,会阻塞正常的AWT事件处理,因此阻止了重绘操作的发生。”也即API本身就是线程不安全的。因为开始我的代码是在run方法内直接写:

progressBar.setValue(jd);

这个操作一直被阻塞了,UI界面的进度条也就实时刷新了

后来改成:

Dimension d = progressBar.getSize();

Rectangle rect = new Rectangle(0, 0, d.width, d.height);

progressBar.setValue(jd);

progressBar.paintImmediately(rect);

才初步解决:

但是现在还有一个问题,就是run方法要持续输出一段文本到控制台(System.out.println("我没有结束"))(也即不是空死循环),不然它就始终抢占不到CPU,没机会执行,CPU一直被复制的主进程抢占,甚至让复制的进制sleep也不会切到run里,可能我的代码还不完善,过几天再来解决吧。

闲话少说,上最终代码:

import java.awt.Color;

import java.awt.Dimension;

import java.awt.GridLayout;

import java.awt.Rectangle;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import javax.swing.JButton;

import javax.swing.JFileChooser;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.JPanel;

import javax.swing.JProgressBar;

import javax.swing.JTextField;

public class Exp10_3 extends JFrame implements Runnable {

boolean b = false;// 线程执行的标志

int jd = 0;// 当前进度

long sum = 0;// 当前共复制的长度

JButton button1 = new JButton("被复制");

JTextField beCyFile = new JTextField(30);

JButton button2 = new JButton("复制到");

JTextField CyToDir = new JTextField(30);

JButton Start = new JButton("开始复制");

JLabel label = new JLabel("进度");

JProgressBar progressBar = new JProgressBar();

void initUI() {

JPanel top1 = new JPanel();

JPanel top2 = new JPanel();

JPanel end = new JPanel();

top1.add(button1);

top1.add(beCyFile);

top2.add(button2);

top2.add(CyToDir);

setLayout(new GridLayout(4, 1));

add(top1);

add(top2);

add(Start);

progressBar.setStringPainted(true);// 设置进度条上字符串可显示

progressBar.setBackground(Color.GREEN);// 设置进度条颜色

end.add(label);

end.add(progressBar);

add(end);

button1.addActionListener(new ActionListener() {

// 将选择文件的绝对路径显示到被复制后的文本框内

@Override

public void actionPerformed(ActionEvent e) {

JFileChooser fc = new JFileChooser();

fc.setFileHidingEnabled(false);// 显示隐藏文件

fc.setMultiSelectionEnabled(false);// 允许多选

fc.setDialogTitle("请选择要复制的文件");

if (fc.showOpenDialog(Exp10_3.this) == JFileChooser.APPROVE_OPTION) {

beCyFile.setText(fc.getSelectedFile().getAbsolutePath());

CyToDir.setText(fc.getSelectedFile().getParent());// 获取file文件的父目录(强大的API) 自我设定:默认复制到同一目录

}

}

});

button2.addActionListener(new ActionListener() {

@Override

public void actionPerformed(ActionEvent e) {

JFileChooser fc = new JFileChooser();

fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);// 仅仅能选择目录

fc.setDialogTitle("请选择要复制到的路径");

if (fc.showOpenDialog(Exp10_3.this) == JFileChooser.APPROVE_OPTION) {

CyToDir.setText(fc.getSelectedFile().getAbsolutePath());

}

}

});

Start.addActionListener(new ActionListener() {

@Override

public void actionPerformed(ActionEvent e) {

jd = 0;

b = true;

try {

String file1Path = beCyFile.getText();

File file1 = new File(beCyFile.getText());// 被复制的文件

String file2Path = CyToDir.getText() + "\\copy" + file1.getName();// 复制完后新文件路径名

File file2 = new File(file2Path);// 新建复制文件

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file1Path));

BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file2Path));

byte[] be = new byte[1024 * 1024];// 之前定义为b和boolean重复了 屏蔽了全局标志b

int len = bis.read(be);

long sum = 0;

long file1len = file1.length();

while (-1 != len) {

bos.write(be, 0, len);// 一次读一个字节数组 换行也会读 不用自动换行了

bos.flush();

sum += len;

jd = (int) (sum * 1.0 / file1len * 100);// 之前没有乘1.0 且多写了一个(int) 导致jd一直是0 最后一次突变100

len = bis.read(be);

}

最后再绘一次

Dimension d = progressBar.getSize();

Rectangle rect = new Rectangle(0, 0, d.width, d.height);

progressBar.setValue(jd);

progressBar.paintImmediately(rect);

b = false;

System.out.println("b=" + b);

} catch (IOException e1) {

e1.printStackTrace();

}

}

});

Thread t = new Thread(this);

t.start();

pack();

setLocationRelativeTo(null);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

}

public static void main(String[] args) {

Exp10_3 t = new Exp10_3();

t.initUI();

}

@Override

public void run() {

while (true) {

if (b) {

//progressBar.setValue(jd);//之前run内就这一行,进度条一直不刷新

Dimension d = progressBar.getSize();

Rectangle rect = new Rectangle(0, 0, d.width, d.height);

progressBar.setValue(jd);

progressBar.paintImmediately(rect);

if (jd == 100) {

b = false;

//System.out.println("run内b=" + b);// 不能写return 此进程不能结束 一直开着

}

}

//System.out.println("我没有结束");//删了此行进度条就又不刷新了

//第一次改进 上面一行换成下面5行 即输出操作改成停顿1ms

try {

Thread.sleep(1);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

写报告时发现有了一个更好的改进方法,可以说基本完全解决了这个问题了:

将run方法内的:

System.out.println("我没有结束");//删了此行进度条就又不刷新了

改成:

try {

Thread.sleep(1);

} catch (InterruptedException e) {

// TODO 自动生成的 catch 块

e.printStackTrace();

}

就行了。

让刷新进度的进程有停顿操作就行了  神奇 有停顿操作反而容易抢到CPU,自己还没想到什么好的解释(这几天写坦克大战时又遇到了类似问题,就是暂停与继续操作。必须在sleep之后判断,也即是while(true){}循环体为空的话,cpu似乎将该线程视为垃圾线程,不再执行了。。),不过问题确乎解决了(而且拿图灵祖师爷的模仿游戏电影1.73G试验了下,复制的还挺快的)。大神看了能且知道作何解释的望告知。(代码段已更新)

java 进度条 不更新_java 进度条不能刷新解决方案 (已更新一次)相关推荐

  1. java的人patch方法_java – Spring MVC PATCH方法:部分更新

    我有一个项目,我使用Spring MVC Jackson构建REST服务.让我们说我有以下java实体 public class MyEntity { private Integer id; priv ...

  2. js更新数组对象_7 种Vue 数据已更新而页面没有更新的情况及深化总结(收藏)

    作者:前端1943 链接:https://segmentfault.com/a/1190000022772025 如果你发现你自己需要在 Vue 中做一次强制更新,99.9% 的情况,是你在某个地方做 ...

  3. java 进度条时间设置_java进度条

    练习JProgressBar结合Timer使用. 代码如下: package luojing; import java.awt.*; import java.awt.event.*; import j ...

  4. java jdbc 批量更新_java,jdbc,大量数据update更新效率很慢,哪位大神可怜可怜我吧...

    数据库用的是mysql,部署在windows系统上.前提是不改变这两个条件.Stringsql="updatetableA=?,B=?,C=?whereD=?andE=?";字段D ...

  5. java 图片不能正常移动_Java,我的图像不会更新/移动

    我对Java的东西是一个新手,但是..在网上阅读了很多内容之后,我一直在努力开发这款游戏并开始使用,我正在使用一些图片.我想通过KeyListener来更新他们的立场以展示运动的过程,我相信.不幸的是 ...

  6. java中sql去除游标_java.sql.SQLException:-ORA-01000:已超过最大打开游标

    小编典典 ORA-01000(最大打开游标错误)是Oracle数据库开发中极为常见的错误.在Java上下文中,当应用程序尝试打开比数据库实例上配置的游标更多的ResultSet时,就会发生这种情况. ...

  7. java追加字符串到文件_java 将字符串追加到文件已有内容后面的操作

    我就废话不多说了,大家还是直接看代码吧~ /** * 将字符串追加到文件已有内容后面 * * @param fileFullPath 文件完整地址:D:/test.txt * @param conte ...

  8. java代码解决的问题_java代码规范问题及解决方案

    java代码规范问题总结 1.没有总是检查ResultSet结果对象 解决方案是通过if判断ResultSet结果是有有元素,常用条件是ResultSet结果的next,previous,first, ...

  9. java帳戶登錄_java.sql.SQLException: ORA-28000: 帐户已被锁定

    java.sql.SQLException: ORA-28000: 帐户已被锁定 然后按照以前的办法找到了解锁的方法,想到可能是某个同事登录失败次数过多.因为oracle 默认的策略是oracle11 ...

最新文章

  1. discard connection丢失数据_python kafka 生产者发送数据的三种方式
  2. sql server 数据库备份方案
  3. 一加7充电_夜话丨一加7超级快充明天见
  4. getcwd和pwd为什么不一样_企业职工,公务员为什么缴纳的养老保险不一样呢?
  5. C语言鸡尾酒排序cocktail sort算法(附完整源码)
  6. SAP Spartacus单元测试用例中Component构造函数的调用上下文
  7. jQuery源码研究分析学习笔记-jQuery.extend()、jQuery.fn.extend()(八)
  8. 解决Firefox访问EBS时提示激活Java插件的问题
  9. 在Red Hat Enterprise Linux 5 64-bit安装oracle11g r2
  10. js实现上传文件实时显示缩略图
  11. [影评]《太阳照样升起》
  12. 【学习笔记】神经内科常用量表总结(文后有下载链接)
  13. 将本地代码push到github上
  14. 【深度学习论文阅读】TCN:An Empirical Evaluation of Generic Convolutional and Recurrent Networks for Sequence
  15. aardio - 小窍门及注意事项收集贴
  16. 带你揭秘华为5G为何地表最强
  17. 名帖220 赵孟頫 行书《光福寺重建塔记》
  18. HDU - 4081 Qin Shi Huang's National Road System(次小生成树)
  19. 云平台学习笔记(三)-实践
  20. WSL+oh-my-zsh安装 教程

热门文章

  1. 新版vue-cli搭建多页应用2
  2. 《zabbix用户权限分配管理》-8
  3. MVC增删查改,从数据库到后台,到前端,整个复习一下
  4. SharePoint 2010 新体验5 - Office Web Applications
  5. 博客堂也遇DotText经典Exception
  6. 北京学python去哪里好_北京想学习Python应该去哪里好
  7. linux时间轮算法,关于时间轮的设计 linux hashed Hierarchical timing wheel
  8. 票房破五十亿!用Python分析李焕英为啥能逆袭《唐探3》
  9. java基本数据类型自动转包装类_java基本数据类型和包装类相互转换
  10. Java中intentfiler_【Android - 组件】之IntentFilter的匹配规则