线程相关

创建线程方式:

  1. 继承Thread类
  2. 实现Runnable接口
  3. 通过Callable接口的call方法
  4. 通过创建线程池来创建线程,使用 ExecutorService 的 execute 方法:​​​​​

继承Thread类,然后调用start方法:

class SampleThread extends Thread {
    //重写run方法,线程运行后,跑的就是run方法 
    public void run(){
       //System.out.println("");
    }
 
    public static void main(String[] args){
       Thread t1 = new SampleThread();
       Thread t2 = new SampleThread();
       t1.start();  //线程运行,调用的 run()方法.
       t2.start(); //线程运行,调用的 run()方法..  
    }
} 

实现Runnable接口的run方法, 然后再用Thread类包裹后,调用start方法:

class A implements Runnable{
 
    @Override
    public void run() {
        // implement run method here 
    }
 
    public static void main() {
        final A obj = new A();
 
        Thread t1 = new Thread(new A());
 
        t1.start();
    }
 
}

实现 Callable 接口的 call 方法,用 FutureTask 类包裹 Callable 对象。然后再用 Thread 类包裹 FutureTask 类,并调用 start方法。call() 方法可以有返回值:

class MyCallable implements Callable {
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            sum += i;
        }
        return sum;
    }
 
    public static void main(String[] args) throws Exception {
        MyCallable mc = new MyCallable(); //实例化 callable
 
        FutureTask oneTask = new FutureTask(mc); //用FutureTask包裹
        Thread oneThread = new Thread(oneTask); //用Thread包裹
        oneThread.start();
        System.out.print(oneTask.get()); //获取返回值
    }
}

Callable 方式有以下几个优点:

  • 可以捕获线程上的异常
  • 可以通过 get 方法得到返回值
  • get 方法阻塞当前线程,直到调用的线程运行结束
  • 可以取消线程的运行

通过创建线程池来创建线程,使用 ExecutorService 的 execute方法:

ExecutorService es = Executors.newCachedThreadPool();
Runnable r = <your runnable here>;
es.execute(r);

 

线程的生命周期

       当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5 种状态。尤其是当线程启动以后,它不可能一直"霸占"着 CPU 独自运行,所以 CPU 需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换。

       新建状态(NEW):当程序使用 new 关键字创建了一个线程之后,该线程就处于新建状态,此时仅由 JVM 为其分配内存,并初始化其成员变量的值。

       就绪状态(RUNNABLE):当线程对象调用了 start()方法之后,该线程处于就绪状态。Java 虚拟机会为其创建方法调用栈和程序计数器,等待调度运行。

       运行状态(Running):如果处于就绪状态的线程获得了 CPU,开始执行 run()方法的线程执行体,则该线程处于运行状态。

       阻塞状态(Blocked):阻塞状态是指线程因为某种原因放弃了 cpu 使用权,也即让出了 cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得 cpu timeslice 转到运行(running)状态。阻塞的情况分三种:

              等待阻塞(o.wait->等待对列):

              运行(running)的线程执行 o.wait()方法,JVM 会把该线程放入等待队列(waitting queue)中。

              同步阻塞(lock->锁池):

              运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则 JVM 会把该线程放入锁池(lock pool)中。

              其他阻塞(sleep/join):

              运行(running)的线程执行 Thread.sleep(long ms)或 t.join()方法,或者发出了 I/O 请求时,JVM 会把该线程置为阻塞状态。当 sleep()状态超时、join()等待线程终止或者超时、或者 I/O处理完毕时,线程重新转入可运行(runnable)状态。

       线程死亡(Dead):线程会以下面三种方式结束,结束后就是死亡状态。

              正常结束

              1. run() 或 call() 方法执行完成,线程正常结束

              异常结束

             2. 线程抛出一个未捕获的 Exception 或 Error

              调用 stop

              3. 直接调用该线程的 stop()方法来结束该线程—该方法通常容易导致死锁,不推荐使用

 

sleep() 与 wait() 的区别

  1. 对于 sleep() 方法,我们首先要知道该方法是属于 Thread 类中的。而 wait() 方法,则是属于Object 类中的。
  2. sleep() 方法导致了程序暂停执行指定的时间,让出 cpu 该其他线程,但是他的监控状态依然保持着,当指定的时间到了又会自动恢复运行状态。
  3. 在调用 sleep()方法的过程中,线程不会释放对象锁
  4. 而当调用 wait() 方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用 notify() 方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。

start() 与 run() 的区别

  1. start() 方法用来启动线程,真正实现了多线程运行。这时无需等待 run 方法体代码执行完毕,可以直接继续执行下面的代码。
  2. 通过调用 Thread 类的 start()方法来启动一个线程, 这时此线程是处于就绪状态,并没有运行。
  3. 方法 run() 称为线程体,它包含了要执行的这个线程的内容,线程就进入了运行状态,开始运行 run 函数当中的代码。 Run 方法运行结束, 此线程终止。然后 CPU 再调度其它线程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值