Java多线程并发(1)——创建方式与生命周期

线程的实现/创建方式

1.继承Thread类
Thread类本质上是实现了Runnable接口的一个实例,代表一个线程的实例。启动线程的唯一方 法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线 程,并执行run()方法。

public class MyThread extends Thread {     
public void run() {      
System.out.println("MyThread.run()");
     }
   }   
MyThread myThread1 = new MyThread();   
myThread1.start();  

本机测试

/**
 * 多线程的创建, 方式一:继承Thread类
 *  1,创建一个继承与Thread类的子类
 *  2,重写Thread类的run()方法  -->将此线程执行的操作声明在run方法中
 *  3,创建Thread类的子类对象
 *  4,通过此对象调用start方法
 *
 *  例子:遍历100以内的所有偶数
 *
 * @Author zfj
 * @create 2019/10/25 13:59
 */

class MyThread extends Thread{
    public void run() {
        for(int i=0;i<=100;i++){
            System.out.println(i);
        }
    }
}

public class ThreadTest {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        t1.start();


        //问题二,再启动一个线程
        MyThread t2 = new MyThread();
        t2.start();

        for(int i=0;i<=100;i++){
            System.out.println(i+"*");
        }
    }
}

2.实现Runnable接口
如果自己的类已经extends另一个类,就无法直接extends Thread,此时,可以实现一个 Runnable接口

public class MyThread extends OtherClass implements Runnable{
	public void run(){
    		System.out.println("My Thread.run()");
    }
}

//启动MyThread,需要首先实例化一个Thread,并传入自己的MyThread实例: 
MyThread myThread = new MyThread();   
Thread thread = new Thread(myThread);   
thread.start();
//事实上,当传入一个Runnable target参数给Thread后,Thread的run()方法就会调用 target.run() 
public void run(){
   if(target !=null){
			target.run();
}
}

本机

/**
 * 创建多线程的方式二: 实现runnable接口
 * 1,创建一个实现类runnable接口的类
 * 2,实现类去实现runnable中的抽象方法:run()
 * 3,创建实现类的对象
 * 4,将此对象最为参数传递到Thread类的构造器中,创建Thread类的对象
 * 5,通过Thread类的对象调用start()
 *
 *
 * 比较两种创建线程的方式。
 *
 *  开发中:优先选择: 实现runnable接口的方式
 *    原因:1,实现的方式没有类的单继承的局限性
 *         2, 实现的方式更适合来处理来处理多个线程有共享数据的情况
 *    联系:public class Thread impliments Runnable
 *    相同点:两种方式都重写了run方法,将线程要执行的逻辑声明在run里面。

 * @Author zfj
 * @create 2019/10/26 13:26
 */
class MThread implements Runnable{

    public void run() {
        for(int i=0;i<100;i++){
            if(i%2==0)
                System.out.println(Thread.currentThread().getName()+":"+i+":");
        }
    }
}
public class ThreadTest1 {
    public static void main(String[] args) {
        MThread mThread=new MThread();
        Thread t1 = new Thread(mThread);
        Thread t2=new Thread(mThread);
        t1.setName("线程一");
        t2.setName("线程二");
        t1.start();
        t2.start();
    }
}

3。实现callable

/**
 *
 * 创建线程的方式三:实现callable接口。--------JDK5.0
 *
 *
 * 如何理解实现callable接口的方式创建多线程比实现runnable接口创建多线程方式强大?
 * 1.call可以有返回值
 * 2.call可以抛出异常,被外面的操作捕获,获取异常信息
 * 3.callable是支持泛型的
 *
 * @Author zfj
 * @create 2019/10/28 10:55
 */
//1.创建一个实现callable接口的实现类
class NumThread implements Callable{
    //2.实现call方法,将此线程需要执行的操作声明在call方法中
    public Object call() throws Exception {
        int sum=0;
        for(int i=1;i<=100;i++){
            if(i%2==0){
                System.out.println(i);
                sum+=i;
            }
        }
        return sum;
    }
}
public class ThreadNew {
    public static void main(String[] args) {
        //3.创建callable接口实现类的对象
        NumThread num=new NumThread();

        //4.将此callable接口实现类的对象作为参数传递到Future Task构造器中,创建FutureTask对象
        FutureTask futureTask = new FutureTask(num);
        Object sum = null;

        //5.将futuretask的对象作为参数传递到thread类的构造器中
        new Thread(futureTask).start();

        try {
            //get方法的返回值即为 FutureTask构造器参数Callable实现类重写的call方法的返回值
            //6.获取callable中call的返回值
            sum = futureTask.get();
            System.out.println("和为:"+sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    } 
}

4.使用线程池

/**
 *
 * 创建线程的方式四:使用线程池
 *
 * 好处:
 *      1.提高响应速度(减少了创建线程的时间)
 *      2.降低资源消耗(重复利用线程池中的线程,不需要每次都创建)
 *      3.便于管理
 *
 *
 *
 *
 *    面试题:创建多线程有几种方式? 四种
 *
 * @Author zfj
 * @create 2019/10/28 11:27
 */
class NumberThread implements Runnable{

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

    public void run() {
        for(int i=0;i<=100;i++){
            if(i%2!=0){
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    }
}


public class ThreadPool {
    public static void main(String[] args) {
        //1.提供指定数量的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        ThreadPoolExecutor service1=(ThreadPoolExecutor)executorService;

        //设置线程池的属性
        //System.out.println(executorService.getClass());
        //service1.setCorePoolSize(15);
        //service1.setKeepAliveTime(10000);

        //2。执行指定的线程的操作。需要提供实现runnable接口或callable几口实现类的对象
        executorService.execute(new NumberThread());//适合使用runnable
        executorService.execute(new NumberThread1());//适合使用runnable
       // executorService.submit();//适合使用callable

        executorService.shutdown();

    }
}

生命周期
当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。 在线程的生命周期中,它要经过新建(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)状态。

线程死亡
线程会以下面三种方式结束,结束后就是死亡状态。
正常结束

  1. run()或call()方法执行完成,线程正常结束。
    异常结束
  2. 线程抛出一个未捕获的Exception或Error。
    调用 stop
  3. 直接调用该线程的stop()方法来结束该线程—该方法通常容易导致死锁,不推荐使用。

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值