[javase]多线程(二)

来源:互联网 发布:html标签中使用js变量 编辑:程序博客网 时间:2024/06/07 08:06

加入一个线程
一个线程可以在其他线程调用join()方法,其效果是等待一段时间直到第二个线程结束才继续执行。也可以在调用join()时带上一个超时参数(单位可以是毫秒,秒或纳秒)

使用interrupt()方法可以中断join()方法

package com.javanet.thread;/**  * 加入一个线程 */public class Joining {public static void main(String[] args) {Sleepersleepy= new Sleeper("Sleepy", 1500),grumpy = new Sleeper("Grumpy", 1500);Joinerdopey = new Joiner("Dopey", sleepy),doc = new Joiner("Doc", grumpy);grumpy.interrupt();}}class Sleeper extends Thread {private int duration;public Sleeper(String name, int sleepTime) {super(name);duration = sleepTime;start();}@Overridepublic void run() {try {sleep(duration);} catch (Exception e) {System.out.println(getName() + " was interrupted." +"isInterrupted(); " + isInterrupted());return;}System.out.println(getName() + " has awakened");}}class Joiner extends Thread {private Sleeper sleeper;public Joiner(String name, Sleeper sleeper) {super(name);this.sleeper = sleeper;start();}@Overridepublic void run() {try {sleeper.join();} catch (Exception e) {System.out.println("Interrupted");}System.out.println(getName()+" join completed");}}

创建有响应的用户界面

package com.javanet.thread;import java.io.IOException;/**  * 创建有响应的用户界面*/public class Responsive {public static void main(String[] args) throws IOException {//! new UnresponsiveUI();ResponsiveUI ru = new ResponsiveUI();System.in.read();System.out.println(ru.getD());}}/** * 这是一个无限循环程序,只能通过杀死进程方式关闭程序 */class UnresponsiveUI {private volatile double d = 1;public UnresponsiveUI() throws IOException {while (d > 0) {d = d + (Math.PI + Math.E) / d;}System.in.read();}}class ResponsiveUI extends Thread {private volatile double d = 1;public double getD() {return d;}public void setD(double d) {this.d = d;}public ResponsiveUI() {setDaemon(true);start();}@Overridepublic void run() {while (true) {d = d + (Math.PI + Math.E) / d;}}}

控制台输入1执行的结果

139230.935845773856
捕获异常

由于线程的本质特性,使得你不能捕获从线程中逃逸的异常。一旦异常逃出任务的run()方法,他就会向外传播到控制台,除非你采取特殊的步骤捕获这个错误的异常。在JAVA5之前你可以使用线程组来捕获这些异常,但有了java5,可以用Executor来解决这个问题。

package com.javanet.thread;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/**  * 正常途径无法捕捉线程中的异常信息*/public class ExceptionThread implements Runnable {@Overridepublic void run() {throw new RuntimeException();}public static void main(String[] args) {try {ExecutorService exec = Executors.newCachedThreadPool();exec.execute(new ExceptionThread());} catch (Exception e) {System.out.println("runtime failure");}}}
执行结果

Exception in thread "pool-1-thread-1" java.lang.RuntimeExceptionat com.javanet.thread.ExceptionThread.run(ExceptionThread.java:17)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)at java.lang.Thread.run(Thread.java:745)

未解决上面的问题,我们要修改Executor产生线程的方式。Thread.UncaughtException-Handler是java5的新接口,它允许你在每个线程都附着一个异常处理器。Thread.UncaughtExceptionHandler.uncaughtExcetpion()会在线程因未捕获的异常临近死亡前被调用。为了使用它,我们创建了一个新类型的ThreadFactory,它将在每个新创建的Thread对象上附着一个Thread.UncaughtExcetpionHandler。我们将这个工厂传递给Executors创建新的ExecutorService的方法:

package com.javanet.thread;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.ThreadFactory;public class CaptureUncaughtException {public static void main(String[] args) {ExecutorService exec = Executors.newCachedThreadPool(new HandlerThreadFactory());exec.execute(new ExceptionThread2());}}class ExceptionThread2 implements Runnable {@Overridepublic void run() {Thread t = Thread.currentThread();//System.out.println("run() by " + t); //System.out.println("eh = " + t.getUncaughtExceptionHandler());throw new RuntimeException();}}class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {@Overridepublic void uncaughtException(Thread t, Throwable e) {System.out.println("caught " + e);}}class HandlerThreadFactory implements ThreadFactory {@Overridepublic Thread newThread(Runnable r) {//System.out.println(this + " creating new Thread");Thread t = new Thread(r);//System.out.println("created " + t);t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());//System.out.println("eh = " + t.getUncaughtExceptionHandler());return t;}}
执行结果

caught java.lang.RuntimeException

更简单 的方式在Thread类中设置一个静态域,并将这个处理器设置为默认的未捕获的异常处理器

package com.javanet.thread;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/**  * 设置默认的未捕获异常处理器*/public class SettingDefaultHandler {public static void main(String[] args) {Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());ExecutorService exec = Executors.newCachedThreadPool();exec.execute(new ExceptionThread());}}
执行结果

caught java.lang.RuntimeException

共享受限资源

互斥量:因为锁语句产生了一种相互排斥的效果,所以这种机制称为互斥量

块同步:synchronized

你该什么时候同步呢?

如果你正在写一个变量,它可能接下来将被另一个线程读取,或者正在读取一个上一次已经被另一个线程写过的变量,那么你必须使用同步,并且,读写线程都必须用相同的监视锁同步


package com.javanet.thread;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;/**  * 线程同步 Synchronized*/public class TestSynchronized {public static void main(String[] args) {for (int i = 0; i < 5; i++) {ExecutorService exec = Executors.newCachedThreadPool();exec.execute(new TestSyc(i));}}}class TestSyc implements Runnable {private int id;public TestSyc(int id) {this.id = id;}@Overridepublic void run() {synchronized (TestSyc.class) {System.out.println("开始-"+id);try {TimeUnit.MILLISECONDS.sleep(1000);} catch (Exception e) {e.printStackTrace();}System.out.println("结束-"+id);}}}

执行结果:

开始-0结束-0开始-4结束-4开始-3结束-3开始-2结束-2开始-1结束-1

显示的Lock对象

package com.javanet.thread;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/**  * 描述*/public abstract class IntGenerator {private volatile boolean canceled = false;public abstract int next();public void cancel() { canceled = true; }public boolean isCanceled() { return canceled; }}class EventChecker implements Runnable {private IntGenerator generator;private final int id;public EventChecker(IntGenerator g, int ident) {generator = g;id = ident;}@Overridepublic void run() {while (!generator.isCanceled()) {int val = generator.next();if (val % 2 != 0) {System.out.println(val + " not even!");generator.cancel();}}}public static void test(IntGenerator gp, int count) {System.out.println("Press Control-c to exit");ExecutorService exec = Executors.newCachedThreadPool();for (int i = 0; i < count; i++) {exec.execute(new EventChecker(gp, i));}exec.shutdown();}public static void test(IntGenerator gp) {test(gp, 10);}}
package com.javanet.thread;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/**  * Lock*/public class LockEventGenerator extends IntGenerator {private int currentEventValue = 0;private Lock lock = new ReentrantLock();@Overridepublic int next() {lock.lock();try {++currentEventValue;Thread.yield();++currentEventValue;return currentEventValue;} finally {lock.unlock();}}public static void main(String[] args) {EventChecker.test(new LockEventGenerator());}}
运行结果:

Press Control-c to exit
原子性和易用性

使用synchronized关键字是最安全的方式。

临界区

在其他对象上同步

线程本地储存

终结任务

在阻塞时终结

一个线程可以处于以下四种状态之一:

1、新建(new):当线程被创建时,它只会短暂的处于这种状态。此时它已经分配了必须的系统资源,并执行了初始化。此刻线程已经有资格获得CPU时间了,之后调度器将把这个线程转变为可运行状态或阻塞状态

2、就绪(Runnable):在这种状态下,只要调度器把时间片分配给线程,线程就可以运行。也就是说,在任意时刻,线程可以运行也可以不运行。只要调度器能分配时间片给线程,它可以运行;这不同于死亡和阻塞状态

3、阻塞(Blocked):线程能够运行,但有某个条件阻止它的运行。当线程处于阻塞状态时,调度器将忽略线程,不会分配给线程任何CPU时间。直到线程重新进入就绪状态,它才有可以能执行操作。

4、死亡(Dead):处于死亡或终止状态的线程将不再是可调度的,并且再也不会得到CPU时间,它的任务已结束,或不再是可运行的。任务死亡的通常方式是从run()方法返回。

进入阻塞状态


一个任务进入阻塞状态,可能有如下原因:

1、通过调用sleep(milliseconds)使任务进入休眠状态,在这种情况下,任务在指定的时间内不会运行

2、通过调用wait()使线程挂起。直到线程得到了notify()或notifyAll()消息(或在javase5的java.util.concurrent类库中等价的signal()或signalAll()消息),线程才会进入就绪状态。

3、任务在等待某个输入/输入完成

4、任务试图在某个对象上调用其同步控制方法,但是对象锁不可用,因为另一个任务已经获取了这个锁

中断

被互斥锁阻塞

检查中断

线程之间的协作

wait()与notifyAll()

wait(),设置当前线程等待直到另一个线程调用notify()或notifyAll()方法。有两种形式的wait,第一种接受毫秒数作为参数,含义与sleep方法里参数的意思相同,都是指“在此期间暂停”。但与sleep不同的是①wait期间对象锁是释放的②可以通过notify或notifyAll或令时间到期,从wait中恢复

notify(),唤醒一个等待的线程

notifyAll(),唤醒所有正在等待该锁的所有线程

都是基于Object类的,只能在同步控制方法或同步控制块里调用wait()、notify()或notifyAll()

下面是给汽车抛光打蜡的案例:

package com.javanet.thread;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;/** * 先抛光,再打蜡 */public class WaxOMatic {public static void main(String[] args) throws InterruptedException {Car car = new Car();ExecutorService exec = Executors.newCachedThreadPool();exec.execute(new WaxOff(car));exec.execute(new WaxOn(car));TimeUnit.SECONDS.sleep(5);exec.shutdown();}}class Car {private boolean waxOn = false;public synchronized void waxed() {waxOn = true;notifyAll();}public synchronized void buffed() {waxOn = false;notifyAll();}public synchronized void waitForWaxing() throws InterruptedException {while (waxOn == false) {wait();}}public synchronized void waitForBuffing() throws InterruptedException {while (waxOn == true) {wait();}}}class WaxOn implements Runnable {private Car car;public WaxOn(Car car) {this.car = car;}@Overridepublic void run() {try {while (!Thread.interrupted()) {System.out.println("Waxing On!");TimeUnit.MILLISECONDS.sleep(200);car.waxed();car.waitForBuffing();}} catch (InterruptedException e) {System.out.println("Exiting via interrupt");}System.out.println("Ending Wax On task");}}class WaxOff implements Runnable {private Car car;public WaxOff(Car car) {this.car = car;}@Overridepublic void run() {try {while (!Thread.interrupted()) {car.waitForWaxing();System.out.println("Waxing Off!");TimeUnit.MILLISECONDS.sleep(200);car.buffed();}} catch (InterruptedException e) {System.out.println("Exiting via interrupt");}System.out.println("Ending Wax Off task");}}
执行结果:

Waxing Off!Waxing On!Waxing Off!Waxing On!Waxing Off!Waxing On!Waxing Off!Waxing On!Waxing Off!
生产者与消费者

package com.javanet.thread;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;/** * 生产者与消费者 一个饭店,它有一个厨师和一个服务员。这个服务员必须等待厨师准备好膳食,再上菜,然后继续等待。 * 这是一个任务协作的示例,厨师代表生产者,服务员代表消费者。两个任务必须在膳食生产和消费时进行握手 而系统必须以有序的方式关闭。 */public class Restaurant {public Meal meal;public ExecutorService exec = Executors.newCachedThreadPool();public WaitPerson waitPerson = new WaitPerson(this);public Chef chef = new Chef(this);public Restaurant() {exec.execute(chef);exec.execute(waitPerson);}public static void main(String[] args) {new Restaurant();}}/** * 服务员 消费者 */class WaitPerson implements Runnable {private Restaurant restaurant;public WaitPerson(Restaurant restaurant) {this.restaurant = restaurant;}@Overridepublic void run() {try {while (!Thread.interrupted()) {synchronized (this) {while (restaurant.meal == null) {wait();}}System.out.println("waitperson got " + restaurant.meal);synchronized (restaurant.chef) {restaurant.meal = null;restaurant.chef.notifyAll();}}} catch (Exception e) {System.out.println("waitPerson interrupted");}}}/** * 厨师 生产者 */class Chef implements Runnable {private Restaurant restaurant;private int count = 0;public Chef(Restaurant restaurant) {this.restaurant = restaurant;}@Overridepublic void run() {try {while (!Thread.interrupted()) {// 生产者等待synchronized (this) {while (restaurant.meal != null) {wait();}}if (++count == 10) {System.out.println("out of food, closing!");restaurant.exec.shutdownNow();}System.out.print("Order Up! ");// 唤醒消费者synchronized (restaurant.waitPerson) {restaurant.meal = new Meal(count);restaurant.waitPerson.notifyAll();}TimeUnit.MILLISECONDS.sleep(100);}} catch (InterruptedException e) {System.out.println("chef interrupted");}}}class Meal {private final int orderNum;public Meal(int orderNum) {this.orderNum = orderNum;}public String toString() {return "Meal " + orderNum;}}
执行结果:

Order Up! waitperson got Meal 1Order Up! waitperson got Meal 2Order Up! waitperson got Meal 3Order Up! waitperson got Meal 4Order Up! waitperson got Meal 5Order Up! waitperson got Meal 6Order Up! waitperson got Meal 7Order Up! waitperson got Meal 8Order Up! waitperson got Meal 9out of food, closing!Order Up! waitPerson interruptedchef interrupted
生产者与消费者和队列

package com.javanet.thread;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.BlockingQueue;import java.util.concurrent.LinkedBlockingQueue;import java.util.concurrent.SynchronousQueue;/**  * 生产者与消费者和队列*/public class TestBlockingQueues {static void getKey() {try {new BufferedReader(new InputStreamReader(System.in)).readLine();} catch (IOException e) {e.printStackTrace();}}static void getKey(String message) {System.out.println(message);getKey();}static void test(String msg, BlockingQueue<ListOff> queue) {System.out.println(msg);LiftOffRunner runner = new LiftOffRunner(queue);Thread t = new Thread(runner);t.start();for (int i = 0; i < 5; i++) {runner.add(new ListOff(5));}getKey("Press enter ("+msg+")");t.interrupt();System.out.println("Finished " + msg + " test");}public static void main(String[] args) {test("LinkedBlockingQueue", new LinkedBlockingQueue<ListOff>());test("ArrayBlockingQueue", new ArrayBlockingQueue<ListOff>(3));test("SynchronousQueue", new SynchronousQueue<ListOff>());}}class LiftOffRunner implements Runnable {private BlockingQueue<ListOff> rockets;public LiftOffRunner(BlockingQueue<ListOff> rockets) {this.rockets = rockets;}public void add(ListOff lo) {try {rockets.put(lo);} catch (Exception e) {e.printStackTrace();}}@Overridepublic void run() {try {while (!Thread.interrupted()) {ListOff lo = rockets.take();lo.run();//use this thread}} catch (Exception e) {System.out.println("waking from takes");}System.out.println("Exiting ListOffRunner");}}
执行结果:

LinkedBlockingQueuePress enter (LinkedBlockingQueue)#0(4), #0(3), #0(2), #0(1), #0(ListOff!), #1(4), #1(3), #1(2), #1(1), #1(ListOff!), #2(4), #2(3), #2(2), #2(1), #2(ListOff!), #3(4), #3(3), #3(2), #3(1), #3(ListOff!), #4(4), #4(3), #4(2), #4(1), #4(ListOff!), Finished LinkedBlockingQueue testwaking from takesExiting ListOffRunnerArrayBlockingQueue#5(4), #5(3), #5(2), #5(1), #5(ListOff!), Press enter (ArrayBlockingQueue)#6(4), #6(3), #6(2), #6(1), #6(ListOff!), #7(4), #7(3), #7(2), #7(1), #7(ListOff!), #8(4), #8(3), #8(2), #8(1), #8(ListOff!), #9(4), #9(3), #9(2), #9(1), #9(ListOff!), Finished ArrayBlockingQueue testwaking from takesExiting ListOffRunnerSynchronousQueue#10(4), #10(3), #10(2), #10(1), #10(ListOff!), #11(4), #11(3), #11(2), #11(1), #11(ListOff!), #12(4), #12(3), #12(2), #12(1), #12(ListOff!), #13(4), #13(3), #13(2), #13(1), #13(ListOff!), #14(4), Press enter (SynchronousQueue)#14(3), #14(2), #14(1), #14(ListOff!), Finished SynchronousQueue testwaking from takesExiting ListOffRunner

吐司BlockingQueue

package com.javanet.thread;import java.util.Random;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.LinkedBlockingQueue;import java.util.concurrent.TimeUnit;/**  * 吐司BlockingQueue * 有一台机器具有三个任务:一个制作吐司、一个给吐司抹黄油、另一个在抹过黄油的吐司上涂果酱 * 我们可以通过各个处理之间的BlockingQueue来运行这个吐司制作程序*/public class ToastOmatic {public static void main(String[] args) throws InterruptedException {ToastQueue dryQueue = new ToastQueue(),   butteredQueue = new ToastQueue(),   finishedQueue = new ToastQueue();ExecutorService exec = Executors.newCachedThreadPool();exec.execute(new Toaster(dryQueue));exec.execute(new Butterer(dryQueue, butteredQueue));exec.execute(new Jammer(butteredQueue, finishedQueue));exec.execute(new Eater(finishedQueue));TimeUnit.MILLISECONDS.sleep(5);exec.shutdownNow();}}/** * 吐司 */class Toast {public enum Status { DRY, BUTTERED, JAMMED }private Status status = Status.DRY;private final int id;public Toast(int id) {this.id = id;}public void butter() {status = Status.BUTTERED;}public void jamm() {status = Status.JAMMED;}public Status getStatus() {return status;}public int getId() {return id;}@Overridepublic String toString() {return "Toast " + id + ": " + status;}}/** * 吐司队列 */class ToastQueue extends LinkedBlockingQueue<Toast> { }/** * 制作吐司 并放入队列 */class Toaster implements Runnable {private ToastQueue toastQueue;private int count = 0;private Random rand = new Random(47);public Toaster(ToastQueue toastQueue) {this.toastQueue = toastQueue;}@Overridepublic void run() {try {while (!Thread.interrupted()) {TimeUnit.MILLISECONDS.sleep(100 + rand.nextInt(500));//make toastToast t = new Toast(count++);System.out.println(t);//insert into queuetoastQueue.put(t);}} catch (Exception e) {System.out.println("Toaster interrupted");}System.out.println("Toaster off");}}/** * 涂抹黄油 */class Butterer implements Runnable {private ToastQueue dryQueue, butteredQueue;public Butterer(ToastQueue dryQueue, ToastQueue butteredQueue) {this.dryQueue = dryQueue;this.butteredQueue = butteredQueue;}@Overridepublic void run() {try {while (!Thread.interrupted()) {//blocks until next piece of toast is availableToast t = dryQueue.take();t.butter();System.out.println(t);butteredQueue.put(t);}} catch (Exception e) {System.out.println("Butterer interrupted");}System.out.println("Butterer off");}}/** * 涂抹果酱 */class Jammer implements Runnable {private ToastQueue butteredQueue, finishedQueue;public Jammer(ToastQueue butteredQueue, ToastQueue finishedQueue) {this.butteredQueue = butteredQueue;this.finishedQueue = finishedQueue;}@Overridepublic void run() {try {while (!Thread.interrupted()) {//blocks until next piece of toast is availableToast t = butteredQueue.take();t.jamm();System.out.println(t);finishedQueue.put(t);}} catch (Exception e) {System.out.println("Jammer interrupted");}System.out.println("Jammer off");}}/** * 吃掉吐司 */class Eater implements Runnable {private ToastQueue finishedQueue;private int counter = 0;public Eater(ToastQueue finishedQueue) {this.finishedQueue = finishedQueue;}@Overridepublic void run() {try {while (!Thread.interrupted()) {//blocks until next piece of toast is availableToast t = finishedQueue.take();//verify  that the toast is coming in order,//and that all pieces are getting jammedif (t.getId() != counter++ || t.getStatus() != Toast.Status.JAMMED) {System.out.println(">>>> Error: " + t);System.exit(1);;} else {System.out.println("Chomp!" + t);}}} catch (Exception e) {System.out.println("Eater interrupted");}System.out.println("Eater off");}}

任务间使用管道进行输入/输出

package com.javanet.thread;import java.io.IOException;import java.io.PipedReader;import java.io.PipedWriter;import java.util.Random;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;/**  * 任务间使用管道进行输入/输出*/public class PipedIO {public static void main(String[] args) throws Exception {Sender sender = new Sender();Receiver receiver = new Receiver(sender);ExecutorService exec = Executors.newCachedThreadPool();exec.execute(sender);exec.execute(receiver);TimeUnit.MILLISECONDS.sleep(4);exec.shutdownNow();}}class Sender implements Runnable {private Random rand = new Random(47);private PipedWriter out = new PipedWriter();public PipedWriter getPipedWriter() {return out;}@Overridepublic void run() {try {while (true) {for (char c = 'A'; c <= 'Z'; c++) {out.write(c);}TimeUnit.MILLISECONDS.sleep(rand.nextInt(500));}} catch (IOException e) {System.out.println("Sender write exception");} catch (InterruptedException e) {System.out.println("Sender sleep exception");}}}class Receiver implements Runnable {private PipedReader in;public Receiver(Sender sender) throws IOException {in = new PipedReader(sender.getPipedWriter());}@Overridepublic void run() {try {while (true) {System.out.print("read: " + (char)in.read() + ", ");}} catch (Exception e) {System.out.println("receiver read exception");}}}
执行结果:

read: A, read: B, read: C, read: D, read: E, read: F, read: G, read: H, read: I, read: J, read: K, read: L, read: M, read: N, read: O, read: P, read: Q, read: R, read: S, read: T, read: U, read: V, read: W, read: X, read: Y, read: Z, Sender sleep exceptionreceiver read exception







0 0