美文网首页
第一章 java多线程技能

第一章 java多线程技能

作者: 码农也越野 | 来源:发表于2017-02-27 17:23 被阅读0次

    创建线程的两种方式

    a.、继承Thread类

    b、实现Runable接口

    优缺点分析:Thread类实际上也是实现的runable接口,java中只能单继承,因此继承Thread类的话会有局限。

    线程的启动顺序

    使用多线程技术时,代码的运行结果与代码的执行顺序或者调用顺序无关。是cpu以一种不确定方式或者说是在不确定的时间调用线程中的run方法。

    调用start方法时,只是告诉线程规划器该线程已处于就绪状态,可以调用该线程的run方法。因此执行start不代表该线程立即被执行,调用start方法的顺序不代表线程启动的顺序。

    多次调用start方法时,会抛出IllegalThreadStateException。

    this.getName()和Thread.currentThread().getName()

    getName()方法为Thread类中的方法,实现Runable接口的线程对象不能调用此方法。

    Thread.currentThread().getName()在两种实现线程的方式中都可以用。

    两者是同一个线程对象时,返回结果是一样的。

    当将一个Thread对象当做构造参数传递给另一个Thread对象时,this代表传递的这个对象的引用,Thread.currentThread()代表当前的执行线程对象的引用。

    例如:

    public classmyThreadextendsThread {

    publicmyThread() {

    System.out.println("构造函数:Thread.currentThread().getName()="+Thread.currentThread().getName());

    System.out.println("构造函数:this.getName="+this.getName());

    System.out.println("构造函数:this==Thread.currentThread()"+(this==Thread.currentThread()));

    }

    public voidrun() {

    System.out.println(Thread.currentThread().getName());

    System.out.println(this.getName());

    System.out.println("this==Thread.currentThread()"+(this==Thread.currentThread()));

    }

    public static voidmain(String[] args) {

    Thread thread1 =new myThread();

    thread1.setName("b");

    Thread thread =newThread(thread1);

    thread.setName("a");

    thread.start();

    }

    }

    执行结果为:

    构造函数:Thread.currentThread().getName()=main

    构造函数:this.getName=Thread-0

    构造函数:this==Thread.currentThread()false

    a

    b

    this==Thread.currentThread()false

    停止线程

    a、Thread.stop() 此方法unsafe,已经被废止。因为强制一个线程停止有可能导致一些清理工作无法进行,另外一个情况就是对锁定的对象进行解锁,导致数据得不到同步的处理,出现数据不一致的情况。

    b、建议使用Thread.interrupt(),它是给正在执行的线程打了个标记,并没有立刻停止。特殊情况:如果线程sleep后调用interrupt会报异常。如果先调用interrupt再进入睡眠,则会将睡眠之前的代码逻辑执行完,然后进入睡眠时抛出异常。

    如果想立刻停止线程有两种方法:结合interrupted()判断是否已经停止,然后抛出异常;结合interrupted()判断是否已经停止,然后return。建议抛出异常,这样可以进行一些其他处理操作。更可控。使用return会造成污染。

    c、使用退出标志

    this.interrupted()和this.isInterrupted()

    this.interrupted为静态方法,作用是判断当前线程是否是中断状态,执行后会将状态标志清除为false;

    this.isInterrupted为实例方法,作用是判断Thread对象是否是中断状态。

    suspend和resume线程暂停和恢复

    这两个方法也已经被废弃。原因和stop相似,容易造成数据不一致,或者锁死公共资源。

    yield方法

    - 作用是让出cpu。但是让出多长时间不一定,有可能刚刚让出,又马上获得。

    守护线程

    java中线程分为用户线程和守护线程两种。守护线程通过setDaemon(true)来设置一个线程为守护线程,必需在调用start之前设置,否则抛出异常。作用是守护非守护线程,当进程中没有非守护线程了,守护线程会自动销毁。典型的守护线程有GC(垃圾回收器),servlet容器初始化后生成的服务线程。

    获得线程的返回值

    第一种方法:通过类变量和方法返回数

    publicclassMyThreadextendsThread

    {

    privateString value;

    publicvoidrun()

    {

    value ="通过成员变量返回数据";

    }

    publicstaticvoidmain(String[] args)throwsException

    {

    MyThread thread =newMyThread();

    thread.start();

    thread.join();

    System.out.println("value:"+ thread.value);

    }

    }

    通过join使线程执行从异步变成同步,等线程执行完后获取该线程的变量。

    第二种方法:通过实现callable接口

    importjava.util.concurrent.Callable;

    publicclassMyThread2implementsCallable {

    @Override

    publicString call()throwsException {

    String string="通过实现Callable借口返回";

    returnstring;

    }

    }

    publicstaticvoidmain(String[] args) {

    ExecutorService executorService=Executors.newCachedThreadPool();

    Callable callable=newMyThread2();

    Future future=executorService.submit(callable);

    try{

    if(future.isDone()){

    System.out.println(future.get());

    }

    }catch(Exception e) {

    e.printStackTrace();

    }

    }

    必须使用ExecutorService的submit方法来执行,返回一个Future对象。可以使用isDone()方法检测future是否完成,完成后可以调用get()方法获得future的值,如果直接调用get()方法,get()方法将阻塞值线程结束。

    线程池

    类的继承关系:

    ThreadPoolExcuter--->AbstractExcuterService-->ExcuterService-->Excuter

    构造器参数:

    a、 corePoolSize  核心池线程数。创建线程池后,默认里面是空的,知道有任务进来,开始创建线程。可以调用pre方法预先生成corePoolSize个线程。创建的线程数大于corePoolSize时,则会把任务放进缓存队列中。

    b、 maximumPoolSize最大线程数 

    c、 keepAliveTime  线程存活时长 。表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;

    d、unit:参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性。

    e、workQueue:一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,一般来说,这里的阻塞队列有以下几种选择:

    ArrayBlockingQueue;

    LinkedBlockingQueue;

    SynchronousQueue;

    f、threadFactory:线程工厂,主要用来创建线程;

    g、handler:表示当拒绝处理任务时的策略,有以下四种取值:

    ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。

    ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。

    ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)

    ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

    相关文章

      网友评论

          本文标题:第一章 java多线程技能

          本文链接:https://www.haomeiwen.com/subject/osezwttx.html