java多线程

一、什么是进程和线程

        进程就是一个独立的运行程序,它是操作系统进行资源分配和调度的一个独立单位,每个进程拥有独立的地址空间,地址空间包括代码区、数据区和堆栈区,进程之间的地址空间是隔离的,互不影响。

        线程是进程的一部分,它是CPU资源分配的最小单元 ,线程会共享进程中的内存,线程也有独立的空间(栈、程序计数器),一个进程至少有一个线程。

二、java多线程实现方式

java中实现多线程的方式主要有三种:Tread类、Runnable接口、Callable接口。

继承Thread类

 1. 创建一个TestThread类继承Thread类,同时需要重写run()。

public class TestThread extends Thread {

    /**
     * TestThread的构造器 为当前子线程设置一个名字
     * @param name
     */
    public TestThread(String name){
        super(name);
    }
    @Override
    public void run() {
        //继承Thread类 需要重写run方法
        //run() 为我们需要执行的程序
        for (int i=1 ; i<=20; i++){
            System.out.println(this.getName()+"----"+i);
        }
    }
}

2. 开启子线程,首先实例化对象后,直接调用start()即可开启子线程。

//创建一个线程的对象
TestThread th = new TestThread("TestMain的子线程1");

//开启线程
th.start();

实现Runnable接口

 1. 创建一个TestRunnabled类实现Runnabled接口,同时需要重写run()。

/*
    通过实现Runnable接口来创建线程
 */
public class TestRunnable implements Runnable {
    /**
     * 必须要实现run方法
     */
    @Override
    public void run() {
        //线程需要执行的程序
        for (int i=1; i<=20; i++){
            System.out.println(Thread.currentThread().getName()+"----"+i);
        }
    }
}

2. 开启子线程,首先实例化TestRunnable对象后,将该对象传参到Thread类中,通过Thread类的对象来开启。从这里也看出TestRunnable实际上也是对Thread的封装。

//方法二 通过实现Runnable接口 无返回值 不能抛出异常
TestRunnable tr = new TestRunnable();
Thread t = new Thread(tr,"TestMain的子线程2");
t.start();

实现Callable接口

1. 创建一个TestCallabled类实现Callabled接口,同时需要重写call()。

import java.util.concurrent.Callable;

public class TestCallable implements Callable {
    @Override
    public Object call() throws Exception {

        for (int i =1 ; i<=20;i++){
            System.out.println(Thread.currentThread().getName()+"------"+i);
        }
        return Thread.currentThread().getName()+"执行完成了";
    }
}

2. 调用方在开启子线程时,先创建一个TestCallable对象然后需要借用FutureTask对象返回 Runnable 对象,然后再传给Thread类。从这里也看出这种方式在开启子线程时比上面两种方式都要复杂一些。

//方式三 通过实现Callable接口 有返回值  可以抛出异常
TestCallable tc = new TestCallable();
Runnable ft = new FutureTask(tc);
Thread t2 = new Thread(ft,"TestMain的子线程3");
t2.start();

三种方式的区别

1. 第一种方式,由于直接继承Thread类,而java又是单继承,因此它没法继承其他的类。它是没有返回值的,也无法抛异常。

2. 第二种方式,通过实现Runnable接口,所以还可以继承其他类,完成其他类的功能,它也没有返回值,也无法抛异常。

3. 第三种方式,是从JDK1.5之后开始推出,通过实现Callable接口,中间再借用FutureTask来实现,它的好处是有返回值,也可以抛异常。但在获取返回值时需注意,它会阻塞其他线程的执行。

三、线程的的生命周期

线程生命周期如图:

线程的主要状态流转: 新生状态-> 就绪状态 -> 运行状态/阻塞状态 ->死亡状态。
新生状态:当一个线程对象被创建时,这线程的状态就是新生状态,此时这个线程还没开启,并不会被CPU调度执行。

就绪状态:当执行start()后,线程正式开启,等待CPU的调度中,这时的状态就是就绪状态。

运行状态:当获取到CPU资源后,程序正在执行中的状态。

阻塞状态:当程序执行中出现了阻塞事件,线程则进入到阻塞状态中,直到阻塞事件结束后,状态重新回到了就绪状态。

死亡状态:程序执行完成,或者出现异常导致程序退出时,该线程则执行完成进入到死亡状态。

总结:

        多线程能够充分发挥计算机多核的能力,多核计算机可以同时执行多个线程。如果计算机只有单核时,其实程序在执行的本质上还是同步执行的,只不过CPU会划分为很多的时间片,然后通过调度时间片去执行不同线程的程序,只不过这些时间片的时间非常小,这就给大家带来了单核执行多线程的效果。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值