Java学习总结:26

线程与进程

进程是程序的一次动态执行过程,它经历了从代码加载、执行到执行完毕的一个完整过程,这个过程也是进程本身从产生、发展到最终消亡的过程。
线程是比进程更小的执行单位,线程是在进程的基础上进行的进一步划分,一个进程可能包含多个同时执行的线程。进程与线程的区别

注意:所有的线程一定要依附于进程才能够存在,进程一旦消失,线程也一定会消失。 而Java是为数不多的支持多线程的开发语言之一。

多线程实现

在Java中,如果要想实现多线程的程序,就必须依靠一个线程的主类体(表示的是一个线程的主类)。但是这个线程的主类体在定义时也需要有一些特殊要求,即此类需要继承Thread类或实现Runnable(Callable)接口来完成定义。

继承Thread类

java.lang.Thread是一个负责线程操作的类,任何类只需要继承Thread类就可以成为一个线程的主类。线程主类的定义格式如下:

class 类名称 extends Thread{	//继承Thread类
	属性...;					//类中定义属性
	方法...;					//类中定义方法
	public void run(){			//覆写Thread类中的run()方法,此方法是线程的主体
		线程主体方法;
	}
}

例:启动多线程

package Project.Study.Multithreading;
import java.lang.Thread;

class MyThread extends Thread{		//这就是一个多线程的操作类
    private String name;			//定义类中的属性
    public MyThread(String name){	//定义构造方法
        this.name=name;
    }
    @Override
    public void run(){				//覆写run()方法,作为线程的主操作方法
        for (int x=0;x<200;x++){
            System.out.println(this.name+"-->"+x);
        }
    }
}
public class Test1 {
    public static void main(String[] args){
        MyThread mt1=new MyThread("线程A");	//实例化多线程对象
        MyThread mt2=new MyThread("线程B");
        MyThread mt3=new MyThread("线程C");
        mt1.start();						//启动多线程
        mt2.start();
        mt3.start();
    }
}
//结果
//线程B-->0
//线程C-->0
//线程A-->0
//线程C-->1
//线程B-->1
//线程C-->2
//后面省略...

注意:直接调用run()方法,并不能启动多线程,多线程启动的唯一方法就是Thread类中的start()方法:public void start()(调用此方法执行的方法体是run()方法定义的代码)

实现Runnable接口

Thread类实现多线程最大的缺点就是单继承的问题,因此Java中也可以利用Runnable接口来实现多线程。这个接口定义如下:

@FunctionalInterface		//函数式接口
public interface Runnable{
    public void run();
}

例:使用Runnable实现多线程

package Project.Study.Multithreading;

class MyTread2 implements Runnable{	//定义线程主体类
    private String name;			//定义类中的属性
    public MyTread2(String name){	//定义构造方法
        this.name=name;
    }
    @Override
    public void run(){				//覆写run()方法
        for(int x=0;x<200;x++){
            System.out.println(this.name+"-->"+x);
        }
    }
}
public class Test2 {
    public static void main(String []args){
        MyTread2 mt1=new MyTread2("线程A");	//实例化多线程类对象
        MyTread2 mt2=new MyTread2("线程B");
        MyTread2 mt3=new MyTread2("线程C");
        new Thread(mt1).start();			//使用Thread启动多线程
        new Thread(mt2).start();
        new Thread(mt3).start();
    }
}
//结果:
//线程C-->0
//线程A-->0
//线程B-->0
//线程A-->1
//线程C-->1
//线程C-->2
//后面省略...

例:使用Lambda表达式操作

package Project.Study.Multithreading;

public class Test2 {
    public static void main(String []args){
        String name="线程对象";
        new Thread(()->{
            for(int x=0;x<200;x++){
                System.out.println(name+"-->"+x);
            }
        }).start();
    }
}
//结果:
//线程对象-->0
//线程对象-->1
//线程对象-->2
//线程对象-->3
//线程对象-->4
//线程对象-->5
//后面省略...

利用Callable接口实现多线程

Callable接口解决了Runnable接口里的run()方法不能返回操作结果的问题。
该接口的定义如下:

@FunctionalInterface
public interface Callable{
    public V call() throws Exception;
}

定义一个线程主体类

import java.util.concurrent.Callable;
class MyThread3 implements Callable<String>{	//多线程主体类
    private int ticket=10;						//卖票
    @Override
    public String call() throws Exception{
        for(int x=0;x<100;x++){
            if(this.ticket>0){					//还有票可以出售
                System.out.println("卖票,ticket="+this.ticket--);
            }
        }
        return "票已卖光!";						//返回结果
    }
}

当多线程的主体类定义完成后,要利用Thread类启动多线程,但是在Thread类中并没有定义任何构造方法可以直接接收Callable接口对象实例,并且由于需要接收call()方法返回值的问题,Java提供了一个java.util.concurrent.FutureTask< V >类,定义如下:

public class FutureTask<V>
extends Object
implements RunnableFuture<V>

在这里插入图片描述
在这里插入图片描述
例:启动多线程

package Project.Study.Multithreading;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

class MyThread3 implements Callable<String>{
    private int ticket=10;
    @Override
    public String call() throws Exception{
        for(int x=0;x<100;x++){
            if(this.ticket>0){
                System.out.println("卖票,ticket="+this.ticket--);
            }
        }
        return "票已卖光!";
    }
}
public class Test3 {
    public static void main(String []args)throws Exception{
        MyThread3 mt1=new MyThread3();					//实例化多线程对象
        MyThread3 mt2=new MyThread3();
        FutureTask<String>task1=new FutureTask<>(mt1);
        FutureTask<String>task2=new FutureTask<>(mt2);
        //FutureTask是Runnable接口子类,所以可以使用Thread类的构造来接收task对象
        new Thread(task1).start();						//启动第一个多线程
        new Thread(task2).start();						//启动第二个多线程
        //多线程执行完毕后可以取得内容,依靠FutureTask的父接口Future中的get()方法实现
        System.out.println("A线程返回的结果:"+task1.get());
        System.out.println("B线程返回的结果:"+task2.get());
    }
}
//结果:
//卖票,ticket=10
//卖票,ticket=9
//卖票,ticket=10
//卖票,ticket=9
//卖票,ticket=8
//卖票,ticket=8
//卖票,ticket=7
//卖票,ticket=7
//卖票,ticket=6
//卖票,ticket=6
//卖票,ticket=5
//卖票,ticket=5
//卖票,ticket=4
//卖票,ticket=4
//卖票,ticket=3
//卖票,ticket=2
//卖票,ticket=1
//卖票,ticket=3
//卖票,ticket=2
//卖票,ticket=1
//A线程返回的结果:票已卖光!
//B线程返回的结果:票已卖光!

本程序利用FutureTask类实现Callable接口的子类包装,由于FutureTask是Runnable接口的子类,所以可以利用Tread类的start()方法启动多线程,当线程执行完毕后,可以利用Future接口中的get()方法返回线程的执行结果。

线程的操作状态

任何线程一般都具有5个状态,即:创建、就绪、运行、堵塞和终止。
在这里插入图片描述

1.创建状态

在程序中用构造方法创建一个线程对象后,新的线程对象便处于新建状态,此时,它具有相应的内存空间和其他资源,但还处于不可运行的状态。

2.就绪状态

新建线程对象后,调用该线程的start()方法就可以启动线程。当线程启动,线程就进入就绪状态。此时,线程将进入线程队列排队,等待CPU服务,这表明它已经具备了运行条件。

3.运行状态

当就绪状态的线程被调用并获得处理器资源时,线程就进入了运行状态。此时,自动调用该线程对象的run()方法。

4.堵塞状态

一个正在执行的线程在某些特殊情况下,如被人为挂起或需要执行耗时的输入输出操作时,将让出CPU并暂时中止自己的执行,进入堵塞状态。在可执行状态下,如果调用sleep()、suspend()、wait()等方法,线程都将进入堵塞状态。堵塞时,线程不能进入排队队列,只有引起堵塞的原因被消除后,线程才可以转入就绪状态。

5.终止状态

线程调用stop()方法或run()方法执行结束后,就处于终止状态。处于终止状态的线程不具有继续运行的能力。

发布了49 篇原创文章 · 获赞 25 · 访问量 1522

猜你喜欢

转载自blog.csdn.net/weixin_45784666/article/details/104957664
今日推荐