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
Two roads diverged in a wood
I took both of them