多进程与多线程的区别?本质的区别在于每个进程拥有自己的一整套变量,而线程则共享数据。共享变量使线程之间的通信比进程之间的通信更有效、更容易。
此外,在有些操作系统中,与进程相比较,线程更“轻量级”,创建、撤销一个线程比启动新进程的开销要小得多。
这里从察看一个没有使用多线程的程序开始。用户很难让它执行多个任务。在对其进行剖析之后,将展示让这个程序运行几个彼此独立的多个线程是很容易的。这个程序采用不断地移动位置的方式实现球跳动的动画效果, 如果发现球碰到墙壁, 将进行重绘(见下图所示 )。
当点击开始按钮时, 程序将从屏幕的左上角弹出一个球, 这个球便开始弹跳。开始按钮的处理程序将调用 addBall 方法。这个方法循环运行 1000 次 move。 每调用一次 move,球就会移动一点, 当碰到墙壁时, 球将调整方向,并重新绘制面板。
如果运行这个程序, 球就会自如地来回弹跳, 但是, 这个程序完全控制了整个应用程序。如果你在球完成 1000 次弹跳之前已经感到厌倦了,并点击 关闭 按钮会发现球仍然还在弹跳。在球自己结束弹跳之前无法与程序进行交互。
显然,这个程序的性能相当糟糕。人们肯定不愿意让程序用这种方式完成一个非常耗时的工作。 毕竟,当通过网络连接读取数据时, 阻塞其他任务是经常发生的, 有时确实想要中断读取操作。 例如,假设下载一幅大图片。当看到一部分图片后,决定不需要或不想再看剩余的部分了, 此时,肯定希望能够点击 Stop 按钮或 Back 按钮中断下载操作。下一节将介绍如何通过运行一个线程中的关键代码来保持用户对程序的控制权。
程序清单给出了这个程序的代码。可以直接使用的代码哦~~~
public class Bounce { public static void main(String[] args) { EventQueue.invokeLater(() -> { JFrame frame = new BounceFrame1(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); }); } } /** * 拥有小球组件和按钮的框架 */ class BounceFrame1 extends JFrame { private BallComponent component; public static final int STEPS = 1000; public static final int DELAY = 3; /** * Constructs the frame with the component for showing the bouncing ball and “开始” and “关闭” buttons */ public BounceFrame1() { setTitle("Bounce"); component = new BallComponent(); add(component, BorderLayout.CENTER); JPanel buttonPanel = new JPanel(); addButton(buttonPanel, "开始", event -> addBall()); addButton(buttonPanel, "关闭", event -> System.exit(0)); add(buttonPanel, BorderLayout.SOUTH); pack(); } /** * 向容器中添加一个按钮 * * @param c 容器 * @param title 按钮标题 * @param listener 按钮监听事件 */ public void addButton(Container c, String title, ActionListener listener) { JButton button = new JButton(title); c.add(button); button.addActionListener(listener); } public void addBall() { try { Ball ball = new Ball(); component.add(ball); for (int i = 1; i <= STEPS; i++) { ball.move(component.getBounds()); component.paint(component.getGraphics()); Thread.sleep(DELAY); } } catch (Exception e) { System.out.println("出错啦~~~~"); } } } /** * 画小球的组件 */ class BallComponent extends JPanel { private static final int DEFAULT_WIDTH = 450; public static final int DEFAULT_HEIGHT = 350; List<Ball> balls = new ArrayList<>(); /** * 向组件中添加小球 * * @param ball 小球 */ public void add(Ball ball) { balls.add(ball); } @Override public void paintComponent(Graphics graphics) { // erase background super.paintComponent(graphics); Graphics2D g2 = (Graphics2D) graphics; for (Ball ball : balls) { g2.fill(ball.getShape()); } } @Override public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } } /** * A ball that moves and bounces off the edges of a rectangle */ class Ball { public static final int XSIZE = 15; public static final int YSIZE = 15; private double x = 0; private double y = 0; private double dx = 1; private double dy = 1; /** * Moves the ball to the next position, reversing direction if it hits one of the edges * * @param bounds */ public void move(Rectangle2D bounds) { x += dx; y += dy; if (x < bounds.getMinX()) { x = bounds.getMinX(); dx = -dx; } if (x + XSIZE >= bounds.getMaxX()) { x = bounds.getMaxX() - XSIZE; dx = -dx; } if (y < bounds.getMinY()) { y = bounds.getMinY(); dy = -dy; } if (y + YSIZE >= bounds.getMaxY()) { y = bounds.getMaxY() - YSIZE; dy = -dy; } } /** * Gets ths shape of the ball at its current position * * @return */ public Ellipse2D getShape() { return new Ellipse2D.Double(x, y, XSIZE, YSIZE); } }
完结!