• Java中的多线程(转)


    多线程的简单实现过程:

    (1)将任务处理代码移到实现了Runnable接口的类的run方法中。这个接口非常简单,只有一个方法:

    public interface Runnable

    {

    void run();

    }

    实现这样一个类:

    class MyRunnable implements Runnable

    {

    public void run()

    {

     

    }

    }

    创建一个这个类的对象:

    Runnable r=new MyRunnable();

    再由Runnable创建一个Thread对象:

    Thread t=new Thread(r);

    启动线程:

    t.start();

    (2)还有一种在代码书写上比较方便的方法,创建Thread类的子类。

    class MyThread extends Thread

    {

    public void run()

    {

     

    }

    }

    创建这个类的一个对象,然后调用start方法。

    注意,如果线程很少,可以使用以上方法,如果线程太多,建议使用线程池。

    2009.5.23

    线程的中断:

    Java中线程是不能强制中断的,相反的,每一个线程都有一个中断状态标志位。当外部代码想终止某个线程时,可以调用这个线程的interrupt方法。调用后,此线程的中断状态标志位自动设置为真(isInterrupted()==true),如果此线程中有对中断状态标志位的判断,则可以决定是否响应中断请求。

    以上是什么意思呢?就是说,线程会判断是否有人想中断自己,如果有人想中断,则自己可以决定是不是真的中断,如果这个线程非常重要,则完全可以不理会中断请求而继续执行。

    所以,典型的线程代码如下:

    while(!Thread.currentThread().isInterrupted())

    {

     

    }

    当然,这个代码还不是全部的,因为,还有另一种情况没有处理,那就是,如果当前线程正在sleep或者wait怎么办呢?

    当调用某线程的interrupt方法而此线程正在休眠时,将在此线程内部产生InterruptedException异常,以中断线程的sleep或者wait。其实我们发现在sleep时,Java强制要求加try,就是为了捕获这个异常。一个典型的sleep代码如下:

    try {

    Thread.sleep(1000);

    } catch (InterruptedException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    此时代码正在Thread.sleep(1000)这一行阻塞着呢,突然被interrupt,就跳到catch里了。

    所以,一个线程的典型代码结构有两个,第一个是不经常sleep的:

    public void run()

    {

    try

    {

    ......

    while(!Thread.currentThread().isInterrupted())

    {

     

    }

    }

    catch(InterruptedException e)

    {

    //在sleep或者wait的时候被中断,就会跳到这里

    }

    finally

    {

    //清理现场

    }

    }

    以上代码,由于不经常使用sleep,所以要定期检查中断状态,来处理中断情况。

    如果每一次循环都需要sleep的话,那这个isInterrupted检查就不是必需的了。因为,当代码sleep或wait时,被中断后将直接进入异常处理,如果不在sleep或者wait,那么当调用sleep或wait的时候,sleep或wait会检测到中断状态标志位为真而直接抛出异常。代码如下:

    public void run()

    {

    try

    {

    ......

    while(expression)

    {

     

    Thread.sleep(delay);

    }

    }

    catch(InterruptedException e)

    {

    //被中断了

    }

    finally

    {

    //清理现场

    }

    }

    注意:当sleep抛出异常的同时会清除中断状态。

    注意:有两个非常类似的方法,interrupted和isInterrupted。interrupted是一个静态方法,它检查当前线程是否已被中断。而且调用interrupted方法会清除该线程的中断状态。另一方面,isInterrupted方法是一个实例方法,可以用它来检查是否线程被中断了。调用它不改变中断状态值。

    如果A线程想要等待B线程执行完毕后再执行,则可以这样:

    B.join();

    调用B的阻塞方法,将A阻塞掉,直到B返回。

    在很多发布的代码中,我们经常看到InterruptedException异常被抑制在了一个很低的层次上,像这样:

    void mySubTask()

    {

    ......

    try{sleep(delay);}

    catch(InterruptedException e){}//这里不应该忽略处理代码

    ......

    }

    忽略错误处理是非常不可取的,如果不改动这个结构,则有两个比较合理的选择:

    第一,在catch中加入Thread.currentThread().interrupt()设置中断状态,这样可以保证不破坏中断状态,这样调用者可以对其进行测试。

    第二,更好的选择是,标记出我们的方法将抛出InterruptedException异常,不采用try语句块捕获异常。那么,调用者(或者,最终的run方法)就能够捕获该异常。

    void mySubTask() throws InterruptedException

    {

    ......

    sleep(delay);

    ......

    }

    线程的状态:

    线程有四个状态:

    New(新生):new出来还没有运行的线程,在运行之前还有一些工作要做。

    Runnable(可运行):这里包括两种状态,一种是正在运行,一种是有机会运行,但时间片还没有得到。

    Blocked(被阻塞):线程不能动了。

    Dead(死亡):有自然死亡(run执行完毕)和猝死(run出现异常而未被处理)两类。

    注意:无法确定一个活着的线程是可运行的还是被阻塞了,也无法确定一个可运行的线程是否正在运行。另外,还无法区分死亡线程和非可运行线程。

    线程的同步:

    Java中的典型同步方式有两种:块同步和方法同步,两种方式都用到了synchronized关键字。

    同步方法:

    如果对一个类中的方法添加了synchronized关键字,它就成了同步方法,当一个线程调用这个同步方法的时候,另一个线程调用这个类的所有同步方法时都会阻塞,直到前一个线程调用完毕。

    典型代码如下:

    public synchronized void method()

    {

     

    }

    同步块:

    和VS一样,对某个引用类型对象上锁:

    synchronized(s)

    {

    ......

    s.add();

    ......

    }

    wait和notify是object方法,而不是Thread的方法。wait可以让当前获得锁的线程暂时放弃,让其它正在阻塞的线程有机会执行。如果有wait,在代码的末尾一定要加notify或notifyAll,将放弃锁的线程惊醒。

    wait一般用在两个或多个线程协作上。比如A、B两线程共同操作C,A线程处理C已经很长时间了,B却还没开始。如果需要AB两者执行差距不太大,则A可以先wait,让B有机会处理C。

  • 相关阅读:
    CSS开发中常用技巧总结
    Linq的分组功能
    深入理解 C# 协变和逆变
    js数组删除数组元素!
    关于 Photoshop 蒙版和 Alpha 通道
    jQuery数组处理详解(含实例演示)
    多媒体指令(灰度像素最大值)
    多媒体指令(图像均值模糊)
    matlab练习程序(立体相关块匹配)
    matlab练习程序(steerable filters)
  • 原文地址:https://www.cnblogs.com/bluestorm/p/2625084.html
Copyright © 2020-2023  润新知