1 / 34

Subsystems: Improved exception handling for Java (DRAFT)

Subsystems: Improved exception handling for Java (DRAFT). Bart Jacobs, Frank Piessens. Outline. Try-Catch: Problem + Solution Locking: Problem + Solution Cancellation: Problem + Solution Cleaning Up: Problem + Solution. Outline. Try-Catch: Problem + Solution Locking: Problem + Solution

caesar
Download Presentation

Subsystems: Improved exception handling for Java (DRAFT)

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Subsystems: Improved exception handling for Java (DRAFT) Bart Jacobs, Frank Piessens

  2. Outline • Try-Catch: Problem + Solution • Locking: Problem + Solution • Cancellation: Problem + Solution • Cleaning Up: Problem + Solution

  3. Outline • Try-Catch: Problem + Solution • Locking: Problem + Solution • Cancellation: Problem + Solution • Cleaning Up: Problem + Solution

  4. class Widget { … } class WidgetManager { int count; Widget[] widgets = new Widget[10]; Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } void removeWidget(Widget w) { … } } class Program { public static void main(String[] args) { WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } } … } Problem Statement:A Typical Try-Catch Pattern This program is broken! Why?

  5. class Widget { … } class WidgetManager { int count; Widget[] widgets = new Widget[10]; Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } void removeWidget(Widget w) { … } } class Program { public static void main(String[] args) { WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } } … } Problem Statement:An OutOfMemoryError… m.count == 11 m.widgets.length == 10

  6. class Widget { … } class WidgetManager { int count; Widget[] widgets = new Widget[10]; Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } void removeWidget(Widget w) { … } } class Program { public static void main(String[] args) { WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } } … } Problem Statement:An OutOfMemoryError… 3 4 1 2 m.count == 11 m.widgets.length == 10

  7. class Widget { … } class WidgetManager { int count; Widget[] widgets = new Widget[10]; Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } void removeWidget(Widget w) { … } } class Program { public static void main(String[] args) { WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } } … } Problem Statement:An OutOfMemoryError… 3 4 1 2 5 m.count == 12 m.widgets.length == 10

  8. class Widget { … } class WidgetManager { int count; Widget[] widgets = new Widget[10]; Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } void removeWidget(Widget w) { … } } class Program { public static void main(String[] args) { WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } } … } Problem Statement:A Typical Try-Catch Pattern

  9. class WidgetManager { Subsystem s = Subsystem.getCurrent(); int count; Widget[] widgets = new Widget[10]; Widget allocWidget() { reenter (s) { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } } void removeWidget(Widget w) { … } } class Program { public static void main(String[] args) { WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } } … } Proposed Solution:Re-entering the Owner Subsystem child subsystem root subsystem

  10. class Program { public static void main(String[] args) { WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } } … } class WidgetManager { Subsystem s = Subsystem.getCurrent(); int count; Widget[] widgets = new Widget[10]; Widget allocWidget() { reenter (s) { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } } void removeWidget(Widget w) { … } } Proposed Solution:Re-entering an Outer Subsystem

  11. Subsystems: Basic Operation class Program { public static void main(String[] args) { Subsystem s = Subsystem.getCurrent(); try { reenter (s) { throw new RuntimeException(); } } catch (Throwable t) { System.out.println(t + “ was caught.”); } } } Not caught

  12. Subsystems: Basic Operation class Program { public static void main(String[] args) { try { Subsystem s = Subsystem.getCurrent(); try { reenter (s) { throw new RuntimeException(); } } catch (Throwable t) { System.out.println(t + “ caught by inner.”); } } catch (Throwable t) { System.out.println(t + “ caught by outer.”); } } } Caught by outer

  13. class Subsystem { static Stack<Subsystem> stack = new Stack<Subsystem>(); static { stack.push(new Subsystem(); } Throwable exception; Subsystem parent; List<Subsystem> children = new ArrayList<Subsystem>(); static Subsystem getCurrent() { return stack.peek(); } static void enterNew() { Subsystem s = new Subsystem(); s.parent = getCurrent(); getCurrent().children.add(s); stack.push(s); } static void reenter(Subsystem s) { s.checkNotFailed(); stack.push(s); } static void exit(Throwable e) { if (e != null) getCurrent().setFailed(e); stack.pop(); getCurrent().checkNotFailed(); } void setFailed(Throwable e) { exception = e; for (Subsystemc : children)c.setFailed(e); } void checkNotFailed() { if (exception != null) throw exception; } static void finish(Throwable e) { getCurrent().parent.children.remove(getCurrent()); exit(e); } } Expansion [[try { S } catch (Throwable e) { S’ } ]] = Subsystem.enterNew(); Throwable t = null; try { S } catch (Throwable e) { t = e; } Subsystem.finish(t); if (t != null) { Throwable e = t; S’ } Expansion [[reenter (s) { S } ]] = Subsystem.reenter(s); Throwable t = null; try { S } catch (Throwable e) { t = e; } Subsystem.exit(t); if (t != null) { throw t; } Subsystems: Implementation

  14. Outline • Try-Catch: Problem + Solution • Locking: Problem + Solution • Cancellation: Problem + Solution • Cleaning Up: Problem + Solution

  15. class Widget { … } class WidgetManager { int count; Widget[] widgets = new Widget[10]; synchronized Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } synchronizedvoid removeWidget(Widget w) { … } } class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); new Thread() { public void run() { try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } … } Problem Statement:A Typical Locking Pattern This program is broken! Why?

  16. class Widget { … } class WidgetManager { int count; Widget[] widgets = new Widget[10]; synchronized Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } synchronizedvoid removeWidget(Widget w) { … } } class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); new Thread() { public void run() { try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } … } Problem Statement:An OutOfMemoryError… In thread 1 m.count == 11 m.widgets.length == 10

  17. class Widget { … } class WidgetManager { int count; Widget[] widgets = new Widget[10]; synchronized Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } synchronizedvoid removeWidget(Widget w) { … } } class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); new Thread() { public void run() { try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } … } Problem Statement:An OutOfMemoryError… In thread 1 In thread 2 m.count == 12 m.widgets.length == 10

  18. class WidgetManager { Subsystem s = Subsystem.getCurrent(); int count; Widget[] widgets = new Widget[10]; synchronized Widget allocWidget() { reenter (s) { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } } … } class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); new Thread() { public void run() { try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } … } Subsystems To The Rescue

  19. class WidgetManager { Subsystem s = Subsystem.getCurrent(); int count; Widget[] widgets = new Widget[10]; synchronized Widget allocWidget() { reenter (s) { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } } … } class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); new Thread() { public void run() { try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } … } Subsystems To The Rescue In thread 1

  20. class WidgetManager { Subsystem s = Subsystem.getCurrent(); int count; Widget[] widgets = new Widget[10]; synchronized Widget allocWidget() { reenter (s) { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } } … } class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); new Thread() { public void run() { try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } … } Subsystems To The Rescue In thread 2 In thread 1

  21. class WidgetManager { Subsystem s = Subsystem.getCurrent(); int count; Widget[] widgets = new Widget[10]; synchronized Widget allocWidget() { reenter (s) { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } } … } class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); new Thread() { public void run() { try { … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } … } Subsystems To The Rescue In main thread In thread 2 In thread 1

  22. Subsystems • When an exception occurs in a subsystem s • For safety: New attempts to enter s (or a descendant) rethrow the exception, and • For liveness: Computations executing in s (or a descendant) in other threads are stopped • I.e.: In each thread that is executing in s (or a descendant), an exception is thrown (using Thread.stop()), which is caught when leaving s

  23. Outline • Try-Catch: Problem + Solution • Locking: Problem + Solution • Cancellation: Problem + Solution • Cleaning Up: Problem + Solution

  24. class Task { boolean cancel; Thread thread; synchronized void cancel() { cancel = true; if (thread != null) thread.stop(); } synchronized void setThread(Thread t) { thread = t; if (cancel) throw new ThreadDeath(); } } class Widget { … } class WidgetManager { int count; Widget[] widgets = new Widget[10]; synchronized Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } … } class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); List<Task> tasks = new ArrayList<Task>(); while (true) { String cmd = getUserCommand(); if (cmd.equals(“cancelAll”)) { for (Task t : tasks) t.cancel(); continue; } final Task task = new Task(); tasks.add(task); new Thread() { public void run() { try { task.setThread(Thread.currentThread()); … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } … } Problem Statement:A Typical Cancellation Pattern This program is broken! Why?

  25. class Task { boolean cancel; Thread thread; synchronized void cancel() { cancel = true; if (thread != null) thread.stop(); } synchronized void setThread(Thread t) { thread = t; if (cancel) throw new ThreadDeath(); } } class Widget { … } class WidgetManager { int count; Widget[] widgets = new Widget[10]; synchronized Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } … } class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); List<Task> tasks = new ArrayList<Task>(); while (true) { String cmd = getUserCommand(); if (cmd.equals(“cancelAll”)) { for (Task t : tasks) t.cancel(); continue; } final Task task = new Task(); tasks.add(task); new Thread() { public void run() { try { task.setThread(Thread.currentThread()); … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } … } Problem Statement:A ThreadDeath… ThreadDeath in thread 1 m.count == 11 m.widgets.length == 10

  26. class Task { boolean cancel; Thread thread; synchronized void cancel() { cancel = true; if (thread != null) thread.stop(); } synchronized void setThread(Thread t) { thread = t; if (cancel) throw new ThreadDeath(); } } class Widget { … } class WidgetManager { int count; Widget[] widgets = new Widget[10]; synchronized Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } … } class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); List<Task> tasks = new ArrayList<Task>(); while (true) { String cmd = getUserCommand(); if (cmd.equals(“cancelAll”)) { for (Task t : tasks) t.cancel(); continue; } final Task task = new Task(); tasks.add(task); new Thread() { public void run() { try { task.setThread(Thread.currentThread()); … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } … } Problem Statement:A ThreadDeath… ThreadDeath in thread 1 In thread 2 m.count == 12 m.widgets.length == 10

  27. class Task { boolean cancel; Subsystem subsystem; synchronized void cancel() { cancel = true; if (subsystem != null) subsystem.cancel(); } synchronized void setSubsystem(Subsystem s) { subsystem = s; if (cancel) throw new ThreadDeath(); } } class Widget { … } class WidgetManager { Subsystem s = Subsystem.getCurrent(); int count; Widget[] widgets = new Widget[10]; synchronized Widget allocWidget() { reenter (s) { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } } … } class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); List<Task> tasks = new ArrayList<Task>(); while (true) { String cmd = getUserCommand(); if (cmd.equals(“cancelAll”)) { for (Task t : tasks) t.cancel(); continue; } final Task task = new Task(); tasks.add(task); new Thread() { public void run() { try { task.setSubsystem(Subsystem.getCurrent()); … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } … } Proposed Solution:Subsystem Cancellation

  28. class Task { boolean cancel; Subsystem subsystem; synchronized void cancel() { cancel = true; if (subsystem != null) subsystem.cancel(); } synchronized void setSubsystem(Subsystem s) { subsystem = s; if (cancel) throw new ThreadDeath(); } } class Widget { … } class WidgetManager { Subsystem s = Subsystem.getCurrent(); int count; Widget[] widgets = new Widget[10]; synchronized Widget allocWidget() { reenter (s) { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } } … } class Program { public static void main(String[] args) { final WidgetManager m = new WidgetManager(); List<Task> tasks = new ArrayList<Task>(); while (true) { String cmd = getUserCommand(); if (cmd.equals(“cancelAll”)) { for (Task t : tasks) t.cancel(); continue; } final Task task = new Task(); tasks.add(task); new Thread() { public void run() { try { task.setSubsystem(Subsystem.getCurrent()); … … m.allocWidget() … … … m.removeWidget(…) … … } catch (Throwable t) { showErrorMessage(t); } } }.start(); } } … } Proposed Solution:Subsystem Cancellation (Child subsystem is cancelled) ThreadDeath on entry to child

  29. Outline • Try-Catch: Problem + Solution • Locking: Problem + Solution • Cancellation: Problem + Solution • Cleaning Up: Problem + Solution

  30. class Widget implements Closeable { WidgetManager m; Widget(WidgetManager m) { this.m = m; } public void close() { m.removeWidget(this); } … } class WidgetManager { int count; Widget[] widgets = new Widget[10]; Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } void removeWidget(Widget w) { … } } class Program { static Widget allocGreenWidget(WidgetManager m) { Widget w = m.allocWidget(); w.setColor(Color.green); return w; } public static void main(String[] args) { WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); try { … Widget w = allocGreenWidget(m); try { … } finally { w.close(); } … } catch (Throwable t) { showErrorMessage(t); } } } … } Problem Statement:A Typical Cleanup Pattern This program is broken! Why?

  31. class Widget implements Closeable { WidgetManager m; Widget(WidgetManager m) { this.m = m; } public void close() { m.removeWidget(this); } … } class WidgetManager { int count; Widget[] widgets = new Widget[10]; Widget allocWidget() { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } void removeWidget(Widget w) { … } } class Program { static Widget allocGreenWidget(WidgetManager m) { Widget w = m.allocWidget(); w.setColor(Color.green); return w; } public static void main(String[] args) { WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); try { … Widget w = allocGreenWidget(m); try { … } finally { w.close(); } … } catch (Throwable t) { showErrorMessage(t); } } } … } Problem Statement:A StackOverflowError…

  32. class Widget implements Closeable { Subsystem client = Subsystem.getCaller(); WidgetManager m; Widget(WidgetManager m) { client.registerCleanup(this); this.m = m; } public void close() { m.removeWidget(this); } … } class WidgetManager { Subsystem s = Subsystem.getCurrent(); int count; Widget[] widgets = new Widget[10]; Widget allocWidget() { reenter (s) { Widget w = new Widget(); count++; if (count == widgets.length + 1) { Widget[] ws = new Widget[count * 2]; System.arraycopy(widgets, 0, ws, 0, widgets.length); widgets = ws; } widgets[count – 1] = w; return w; } } void removeWidget(Widget w) { reenter (s) { w.client.unregisterCleanup(w); … } } } class Program { static Widget allocGreenWidget(WidgetManager m) { Widget w = m.allocWidget(); w.setColor(Color.green); return w; } public static void main(String[] args) { WidgetManager m = new WidgetManager(); while (true) { String cmd = getUserCommand(); try { … Widget w = allocGreenWidget(m); try { … } finally { w.close(); } … } catch (Throwable t) { showErrorMessage(t); } } } … } class Subsystem { static void finish(Throwable t) { Subsystem s = getCurrent(); … while (!s.cleanupStack.isEmpty()) s.cleanupStack.peek().close(); } } Proposed Solution:Subsystem Cleanup Routines

  33. Related Work(Under Construction) • Re-entering: Similar to performing a remote procedure call in systems where each subsystem is a separate process/thread • Cancellation: • Rudys, Wallach. Termination in language-based systems. ACM TISS 5(2), 2002. • Wick, Flatt. Memory accounting without partitions. ISMM 2004. • Flatt, Findler. Kill-safe synchronization abstractions. PLDI 2004. • Flatt, Findler, Krishnamurthi, Felleisen. Programming languages as operating systems. ICFP 1999. • Subsystem cleanup stacks: • Similar to compensation stacks in Weimer. Finding and preventing run-time error handling mistakes. OOPSLA 2004.

  34. Conclusion • It’s hard in Java to catch unchecked exceptions safely • Many (most?) existing try-catch blocks for unchecked exceptions are probably unsafe • Many synchronized blocks are probably unsafe • There is no easy and safe way to cancel a computation • Subsystems make it easy to fix these problems for the example programs • Future work: Assess the severity of the problem and the effectiveness of subsystems in large programs

More Related