java 多线程学习(一) 多线程的构造

进程和线程的理解:

进程:从狭义的角度来讲,进程就是一个正在运行的程序的实例

线程:指的是进程中单一顺序的执行流,有时候也叫作轻量级进程。

举个例子: 

      当我们用word 2016程序 编辑word的时候,word2016 可以实时检查拼写的错误。 我们先运行word 2016 程序,

      打开任务管理器,切换到进程页面,就可以找到word2016的进程,这就是正在运行的word2016 的一个实例

java 多线程学习(一) 多线程的构造_第1张图片

同时也可以看到,一个运行的中的程序可能不止有一个进程,可能有多个进程,每个进程都执行不同的任务,如图中的QQ音乐和电脑管家。

我们继续以word2016 来举例说明线程。可以看到在运行的过程中,word只有一个进程,但是却可以同时执行不同的功能。

这是因为word2016 的进程中,有多个线程,如 有一个线程在接收键盘输入的字并以适当的格式显示在屏幕上,而另一个线程在“读取”我们输入的字符或者文本,然后分析并标记错误的部分。

这就和我们以前运行java程序的时候形成对比了。以前我们运行java程序的时候,是从mian函数从上往下按顺序执行的,当调用函数的时候,也要等调用的函数执行完了,才能继续往下执行。而,如果在我们的程序里加入多线程,就可以不用等函数调用完成,可以继续往下执行下面的语句。

多线程的状态

线程从产生到消亡,一共有五个状态

1. Newborn 状态:线程被创建但没有开始执行的初始状态。直到调用Thread类的run()方法后,线程会进入Runable状态

2.Runable状态:线程处在准备就绪的状态,随时可被调用执行。(注意:对线程调用run()方法后,不代表线程立即执行,Runable状态线程会进入一个等待队列中等待执行

3. Running 状态: 线程正在运行的状态,表示线程已经拥有处理器的控制权。正常情况下,当run()方法运行结束后,该线程就进入Dead状态。

4. Blocked状态: 线程的堵塞状态。处于阻塞状态的的线程必须由某些事件唤醒,至于是何种事件,则取决于阻塞发生的原因。

5. Dead 状态: 死亡或终止状态,表示线程已经退出运行的状态。进入这一状态的线程有多方面的原因,可能是线程执行完毕,正常终止也可能是一个线程被另一个线程强行中断。

为了便于理解和记忆,笔者特地画了一个流程图:

java 多线程学习(一) 多线程的构造_第2张图片

构造多线程的三种方法:

一、 通过继承Thread类来构造线程

步骤:

1.创建一个类,并继承(extends)Thread类

2. 重载父类Thread的run()方法(即把你想要在这个线程中执行的代码放入run()方法里

3. 实例化(new)该线程的一个对象

4, 调用对象的start()方法启动线程

ps:线程启动后自动执行run()方法里的内容,执行完毕后,线程进入终止的状态,

下面是一个简单的实例:

//多线程的实现方法之一: 通过继承Thread类实现
public class myThread00 extends Thread {
    public void run(){ //需要重写run方法
        for(int i=0;i<5;i++){
        System.out.println(Thread.currentThread().getName()+" - running");}
    } //Thread.currentThread().getName() 会返回正在执行的该方法的线程的名字,该名字一般由java虚拟机自己生成
    public static void main(String[]args){
        myThread00 mt0=new myThread00();
        myThread00 mt1= new myThread00();
        mt0.start();// 调用start方法而不是run方法啊
        mt1.start();
        for(int i=0;i<5;i++){
            System.out.println("for: "+Thread.currentThread().getName()+" - running");}
    }

}

运行结果如下图:(运行结果不唯一)

java 多线程学习(一) 多线程的构造_第3张图片   java 多线程学习(一) 多线程的构造_第4张图片

(ps: Thread-0 ,Thread-1 ,main 代表三个不同的线程)

读者多运行几次也会得到不同的结果,上面右边的运行结果是比较明显的,可以看出 两个线程是在同时运行的。表现出来的结果就是交替打印(毕竟计算机每秒运算上百万次,所以要想看出更明显的效果,可以把循环的次数适当增大。)

 

需要说明的是,我们在main方法里新建并启动了一个线程,但实际上,还有一个线程在运行main方法,我们这个线程叫做主线程。主线程负责新建和启动其他线程。Thread.currentThread().getName()返回的名字为main即代表该线程是主线程。如在这个例子中, 通过主线程新建并启动了两个子线程。

通过这个简单的例子,我们能得到下面几个结论:

1. 创建独立执行的线程还是比较容易的(Java JVM负责处理了大部分细节)

2. 无法准确的知道线程在什么时间开始执行的(因为这是操作系统决定的)

3. 线程间的执行是相互独立的

4. 线程独立于启动它的线程。

二、通过实现实现Runable接口来构造线程

      我们知道,java类是单继承的,每个类只能有一个父类,所以如果我们通过继承Thread类的方法来构造线程,这个类就不能继承其他需要的类,这可能会对我们的编程造成很大的限制。所以实现多线程一般通过实现Runable接口实现,从而克服了单一继承方式所造成的限制。

      先来看下Runable接口的定义:

public interface Runable{
    public abstract void run();
}

看起来和一般的接口没有什么不一样的,它是怎么实现多线程的呢?答案是 和一个Thread类对象绑定

我们将前面的例子稍微改一下,改成通过实现Runable接口的方式构造线程

//多线程的实现方法之二: 实现Runnable接口。和继承自Thread类差不多,不过实现Runnable后,还是要通过一个Thread来启动:
public class myThread01 implements Runnable{
    @Override
    public void run() {
       for(int i=0;i<5;i++){
           System.out.println(Thread.currentThread().getName()+" - running");
       }
    }
    public static void main(String[] args){

        myThread01 mt1 = new myThread01();//实例化类
        myThread01 mt2 = new myThread01();
       
        Thread t1 = new Thread(mt1); //绑定Thread类对象,并通过Thread类启动
        Thread t2 = new Thread(mt2);

      //Thread t1 = new Thread(new myThread01());  
      //Thread t2 = new Thread(new myThread01()); 这两行和上面四行效果是一样的,是一种简便的写法

        t1.start();//还是通过start方法启动
        t2.start();
        for (int i=0;i<5;i++){
            System.out.println("for: "+Thread.currentThread().getName()+" - running");
        }
    }

运行效果如下(效果不唯一):这是比较明显的结果。。毕竟打印5句话实在是太快了,想看到明显效果的话,可以把循环次数改为500000...

java 多线程学习(一) 多线程的构造_第5张图片

三、在方法二的基础上,可以通过lambda表达式创建线程

ps:lambda表达式是java8加入的特性,如果想要的了解话,可以看看我写的这篇博客

/**
 * 多线程的实现方法之三:
 * //通过lambda表达式方法创建,本质就是实现Runable接口
 *
 * @author manzuo
 */
public class myThread01 {
    public static void main(String[] args) {
        //通过lambda表达式方法创建,本质就是实现Runable接口
        Thread t1 = new Thread(()->{
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + " - running");
            } 
        });
        //还是通过start方法启动
        t1.start();
        for (int i = 0; i < 5; i++) {
            System.out.println("for: " + Thread.currentThread().getName() + " - running");
        }
    }

 

你可能感兴趣的:(java学习,多线程)