java多线程

本文详细介绍了Java中线程的生命周期,包括新建、就绪、运行、阻塞和死亡五个状态,以及各状态间的转换过程。并通过实例演示了如何通过Thread类和Runnable接口创建线程。

线程的调度是JVM的一部分,在一个CPU的机器上上,实际上一次只能运行一个线程

start的方法只是启动了线程,并非真正执行线程,执行线程的是run方法由cpu调度,如果自己手动调用run方法的话,它会像普通方法一样被执行

线程的生命周期:

1.新建状态

用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态。处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态

注意:不能对已经启动的线程再次调用start()方法,否则会出现java.lang.IllegalThreadStateException异常。

2.就绪状态

处于就绪状态的线程已经具备了运行条件,但还没有分配到CPU,处于线程就绪队列(尽管是采用队列形式,事实上,把它称为可运行池而不是可运行队列。因为cpu的调度不一定是按照先进先出的顺序来调度的),等待系统为其分配CPU。等待状态并不是执行状态,当系统选定一个等待执行的Thread对象后,它就会从等待执行状态进入执行状态,系统挑选的动作称之为“cpu调度”。一旦获得CPU,线程就进入运行状态并自动调用自己的run方法。

注意:如果希望子线程调用start()方法后立即执行,可以使用Thread.sleep()方式使主线程睡眠一伙儿,转去执行子线程。

3.运行状态

处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。

处于就绪状态的线程,如果获得了cpu的调度,就会从就绪状态变为运行状态,执行run()方法中的任务。如果该线程失去了cpu资源,就会又从运行状态变为就绪状态。重新等待系统分配资源。也可以对在运行状态的线程调用yield()方法,它就会让出cpu资源,再次变为就绪状态。

当发生如下情况是,线程会从运行状态变为阻塞状态:

3.1线程调用sleep方法主动放弃所占用的系统资源

3.2线程调用一个阻塞式IO方法,在该方法返回之前,该线程被阻塞

3.3线程试图获得一个同步监视器,但更改同步监视器正被其他线程所持有

3.4线程在等待某个通知(notify)

3.5程序调用了线程的suspend方法将线程挂起。不过该方法容易导致死锁,所以程序应该尽量避免使用该方法

当线程的run()方法执行完,或者被强制性地终止,例如出现异常,或者调用了stop()、desyory()方法等等,就会从运行状态转变为死亡状态。

4.阻塞状态

处于运行状态的线程在某些情况下,如执行了sleep(睡眠)方法,或等待I/O设备等资源,将让出CPU并暂时停止自己的运行,进入阻塞状态。 

在阻塞状态的线程不能进入就绪队列。只有当引起阻塞的原因消除时,如睡眠时间已到,或等待的I/O设备空闲下来,线程便转入就绪状态,重新到就绪队列中排队等待,被系统选中后

从原来停止的位置开始继续运行。

5.死亡状态

当线程的run()方法执行完,或者被强制性地终止,就认为它死去。这个线程对象也许是活的,但是,它已经不是一个单独执行的线程。线程一旦死亡,就不能复生。 如果在一个死去的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常

 

以下是基于Thread和Runnable的简单例子,便于学习参考

public class ThreadTest {
    
    public static void main(String[] args) {
         //Thread本身就是一个线程对象  这个线程采用重写run方法的方式
         new Thread(){
            @Override
            public void run() {
                while(true){
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("this is :" + Thread.currentThread().getName());
                }
            }
        }.start();
         
        
        //这个是通过传入Runnable子类对象方式创建线程
        new Thread(new Runnable(){
            @Override
            public void run() {
                while(true){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("this is :" + Thread.currentThread().getName());

                }                
                
            }
        }).start();
        
        
        //把上述两个进行了整合
        new Thread(
                new Runnable(){
                    public void run() {
                        while(true){
                            try {
                                Thread.sleep(500);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            System.out.println("这个不会运行 :" + Thread.currentThread().getName());
                        }                            
                    }
                }
        ){
            public void run() {
                while(true){
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("这个会运行 :" + Thread.currentThread().getName());
                }    
            }
        }.start();
    }
}

控制台打印:

  这个会运行 :Thread-2
  this is :Thread-0
  this is :Thread-1
  这个会运行 :Thread-2
  this is :Thread-0
  这个会运行 :Thread-2

 

 

以上是案例比较简单,这里就不做过多解释;而且实现线程的方式也有很多种,比如直接继承Thread对象(不推荐),或者采用Runnable接口编写自己的实现类等

 

通过Callable接口创建线程(线程有返回值  会把返回的结果存储到Future对象中)

  

public class ThreadTest {
    
    public static void main(String[] args) throws Exception {
        ExecutorService threadPool =  Executors.newSingleThreadExecutor();
        //基于线程池把线程进行submit 
        Future<String> future =
                threadPool.submit(
                        new Callable<String>() {
                            public String call() throws Exception {
                                Thread.sleep(2000);
                                return "hello";
                            };
                        }
                        );
        threadPool.shutdown();
        System.out.println("一直等待,直到有结果为止: ");
        System.out.println("拿到结果:" + future.get());
        
    }
}

输出结果

  
一直等待,直到有结果为止:

拿到结果:hello



 

转载于:https://www.cnblogs.com/weishao-lsv/p/8135712.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值