CS 245 Lecture 25 – Threading for Concurrency

Agenda

  • what ?s
  • threading for parallelism
  • threading for concurrency
  • background tasks
  • animation

FYI

  • Check out Android’s statement about responsiveness┬áin mobile apps.

Code

ImageDownloader.java

package lecture25;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class ImageDownloader extends JFrame {
  private JLabel label;
  private Thread downloaderTask;

  public ImageDownloader() {
    label = new JLabel();
    add(label);

    JButton downloadButton = new JButton("Download");
    downloadButton.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        downloaderTask = new Thread(new DownloaderTask());
        downloaderTask.start();
      }
    });
    add(downloadButton, BorderLayout.NORTH);

    JButton cancelButton = new JButton("Cancel");
    add(cancelButton, BorderLayout.SOUTH);
    cancelButton.addActionListener(e -> downloaderTask.interrupt());

    setSize(512, 512);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setVisible(true);
  }

  private class DownloaderTask implements Runnable {
    @Override
    public void run() {
      try {
        BufferedImage image = ImageIO.read(new URL("http://www.twodee.org/tests/slowimage/slowimage.php"));
        if (!Thread.currentThread().isInterrupted()) {
          SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
              label.setIcon(new ImageIcon(image));
            }
          });
        }
      } catch (IOException e1) {
        e1.printStackTrace();
      }
    }
  }

  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
        new ImageDownloader();
      }
    });
  }
}

Bouncing.java

package lecture25;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Bouncing extends JFrame {
  private ArrayList<Ball> balls;
  private DrawingPanel panel;

  public Bouncing() {
    super("Bouncing");

    balls = new ArrayList<Ball>();
    for (int i = 0; i < 100000; ++i) {
      balls.add(new Ball());
    }
    panel = new DrawingPanel();
    add(panel);

    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setSize(1000, 600);
    setVisible(true);

    new Thread(new Animator()).start();
  }

  private class DrawingPanel extends JPanel {
    @Override
    public void paintComponent(Graphics g) {
      Graphics2D g2 = (Graphics2D) g;

      AffineTransform originalTransform = g2.getTransform();

      g2.scale(1.0, -1.0); // in the space below, origin is upper left, y-axis
                           // points up
      g2.translate(0.0, -getHeight()); // in the space below, origin is bottom
                                       // left, y-axis points up
      g2.scale(getHeight() / 10, getHeight() / 10.0);
      
      for (Ball ball : balls) {
        ball.draw(g2);
      }

      g2.setTransform(originalTransform);
    }
  }

  private static class Ball {
    private Point2D.Double initialPosition;
    private Point2D.Double initialVelocity;
    private Point2D.Double position;
    private Color color;
    private long bornAt;
    private double radius;

    public Ball() {
      Random generator = new Random();

      initialPosition = new Point2D.Double(0, 10);
      initialVelocity = new Point2D.Double(generator.nextDouble() * 5.0, 0.0);
      position = new Point2D.Double(initialPosition.x, initialPosition.y);
      bornAt = System.currentTimeMillis();

      color = new Color(generator.nextFloat(), generator.nextFloat(), generator.nextFloat());
      radius = generator.nextDouble() * 1.0;
    }

    public void draw(Graphics2D g2) {
      g2.setColor(color);
      Ellipse2D.Double ellipse = new Ellipse2D.Double(position.x - radius, position.y - radius, 2 * radius, 2 * radius);
      g2.fill(ellipse);
    }

    public void update(long time) {
      double t = (time - bornAt) / 1000.0;
      position.x = t * initialVelocity.x + initialPosition.x;
      position.y = -4.9 * t * t + initialVelocity.y * t + initialPosition.y;

      if (position.y < radius) {
        bornAt = time;
        initialPosition.x = position.x;
        initialPosition.y = radius;
        initialVelocity.y = -0.7 * (-9.8 * t + initialVelocity.y);
      }
    }
  }

  private class Animator implements Runnable {
    @Override
    public void run() {
      while (true) {
        long timeOfCurrentFrame = System.currentTimeMillis();

        for (Ball ball : balls) {
          ball.update(timeOfCurrentFrame);
        }
        panel.repaint();

        try {
          Thread.sleep(10);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  }

  public static void main(String[] args) {
    new Bouncing();
  }
}

slowimage.php

<?php

$path = 'bunny_normals.png';
$f = fopen($path, 'rb');

sleep(5);

header("Content-Type: image/png");
header("Content-Length: " . filesize($path));

fpassthru($f);
fclose($f);

?>

Haiku

Few things are XOR
Two roads diverged in a wood
I took both of them

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *