2016.6.20笔记(1)-多线程(2)

线程的生命周期

  1. New
    新建 :当线程被创建时,该线程处于新建状态,此时它和其他java对象一样,仅仅由Java虚拟机为其分配了内存,并初始化了其成员变量的值。(此时的线程没有表现出任何表现出任何线程的动态特征,程序也不会执行线程的线程执行体)new Thread()||new Thread(Runnable target,String name)。
  2. Runnable
    就绪:就绪也就是说启动线程,但是启动线程使用start方法,而不是run方法!永远不要调用线程对象的run()方法!调用start方法来启动线程,系统会将该run方法当成线程执行体来处理。如果直接调用线程对象的run方法。则run方法会立即执行,且在这个run方法的执行体未执行结束前其他线程无法并发执行(即系统会将run方法当做一个普通对象的普通方法,而不是线程执行体对待
    附1:如果有一个主线程,一个子线程。当根据逻辑代码该调用子线程时不一定会立即调用,为了想在主线程start()后立即调用子线程,可以考虑使用Thread.sleep(1),这样会让当前线程(主线程)睡眠1毫秒,因为cpu在这1毫秒中是不会休息的,这样就会去执行一条处于就绪状态的线程。
    附2:不能对已经处于就绪状态的线程,再次使用start()
    3.Running
    运行:当处于就绪状态时,该线程获得cpu,执行体开始运行,就处于运行状态了。
    4.Blocked
    阻塞:线程不可能一直处于运行状态(线程执行体足够短,瞬间就可以完成的线程排除),线程会在运行过程中需要被中断,因为是并发,目的是会让其他线程获得执行的机会,线程的调度细节取决于OS采用的策略。(抢占式调度*xp win7 linux unix..)。如果是一些特殊的小型设备可能采用 协作式调度*(只有线程自己调用它的sleep()或yield()才会放弃所占用的资源)。
    1. Dead
      死亡:根据上图所示。测试测试某条线程是否已经死亡,可以调用线程对象的isAlive()方法,当线程处于就绪,运行,阻塞时,返回true。线程处于新建,死亡时返回false。
      不能对已经死亡的线程调用start()方法使它重新启动,死亡就是死亡,是不能再次作为线程执行的。
      当主线程结束时候,其他线程不受任何影响,并不会随之结束。一旦子线程启动起来后,它就拥有和主线程相同的地位,它不会受到主线程的影响。

控制线程

  1. join线程:
    让一个线程等待另一个线程完成的方法:join()。当在某个程序执行流中调用其他线程的join()方法,那该执行流对应的线程就会阻塞,直到被join()加入的join线程完成为止。join方法通常有使用线程的程序调用,将大问题划分成许多小问题,每个小问题分配一个线程。当所有的小问题都得到处理后,再调用 主线程来进一步操作。

为什么要用join()方法
在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了。

    Thread t=new Thread();
    t.start();
    t.join();

简单来说就是加入到t线程。等t线程执行完成后才会返回出来执行线程。)
Join方法有三种重用形式
join():等待被join的线程执行完成
join(long millis):等待join线程的时间最长为millis毫秒,如果在这个时间内,被join的线程还没有执行结束则不再等待)
join(long millis,int nanos)千分之一毫秒(不用)
Code:

public class JoinThread implements Runnable{
@Override
    public void run() {
        for(int i=0;i<5;i++){
        System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }

    public static void main(String [] args) throws InterruptedException{
        //实例化一个Runnable
        JoinThread jt=new JoinThread();
        for(int i=0;i<10;i++){
            if(i==3){
                Thread th=new Thread(jt);
                //启动第二个线程
                th.start();
                //main的线程中调用了th线程的join方法
                //让第二个线程执行完成后再执行main
                th.join();
            }
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

这个例子可能比较好点:
说明:
下面的有两个类Father(主线程类)和Son(子线程类)。因为Son是在Father中创建并启动的,所以,Father是主线程类,Son是子线程类。
在Father主线程中,通过new Son()新建“子线程s”。接着通过s.start()启动“子线程s”,并且调用s.join()。在调用s.join()之后,Father主线程会一直等待,直到“子线程s”运行完毕;在“子线程s”运行完毕之后,Father主线程才能接着运行。 这也就是我们所说的“join()的作用,是让主线程会等待子线程结束之后才能继续运行”!

// 主线程
public class Father extends Thread {
    public void run() {
        Son s = new Son();
        s.start();
        s.join();
        ...
    }
}
// 子线程
public class Son extends Thread {
    public void run() {
        ...
    }
}

后台线程

要将前台线程转换成后台线程,需要在该线程刚新建还未start()之前转换

package com.study.june;

public class DaemonThread implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }

    public static void main(String[] args) {
        // 要将前台线程转换成后台线程,需要在该线程刚新建还未start()之前转换。main线程也是前台线程
        // 所有前台线程死亡时,后台线程也就随之死亡。
        DaemonThread dt = new DaemonThread();
        Thread td = new Thread(dt, "线程1");
        System.out.println("main方法是否是后台线程" + Thread.currentThread().isDaemon());
        System.out.println("td线程最初是否是后台线程" + td.isDaemon());
        // 指定td为后台线程
        td.setDaemon(true);
        System.out.println("td线程执行setDaemon方法后是否是后台线程" + td.isDaemon());
        // 就绪启动后台线程
        td.start();
        for (int i = 0; i < 5; i++) {
            //前台线程,也就是主线程等后台线程结束。要不然太快了,后台线程还没来得及跑...
            Thread.sleep(70);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

总结:sleep和yield区别
- sleep方法暂停当前线程后,会给其他线程执行机会,不会理会其他线程的优先级。而yield只会给优先级>=当前优先级的线程执行机会
- Sleep方法会将线程转入阻塞状态,知道经过阻塞时间才会转入就绪状态。而yield是不会将线程转入阻塞状态的,它只是强制当前线程进入就绪状态。
- Sleep会抛出InterruptedException异常。而yield没有声明任何异常
- Sleep方法比yield方法有更好的移植性。
E.通常不依靠yield来控制并发线程控制

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值