Java 进程与线程 及多线程实现(Thread、Runnable、Callable)

进程与线程的概念

进程: 操作系统中一个程序的执行周期称为一个进程。(是程序的一次动态执行,它对应着从代码加载,执行至执行完毕的一个完整的过程,是一个动态的实体)
windows是一个多进程的操作系统。
线程: :一个程序同时执行多个任务。通常,每一个任务就称为一个线程。与进程相比较,线程更"轻量级",创建、 撤销一个线程比启动一个新进程开销要小的多。没有进程就没有线程,进程一旦终止,其内的线程也将不复存在。
主方法是一个线程。
多进程与多线程区别: 本质区别在于,每个进程拥有自己的一整套变量,而线程则共享数据。共享变量使得线程之 间的通信比进程之间通信更有效、更方便。

多线程表现:一个浏览器应用可以同时下载多个图片、音乐;一个Web服务器需要同时 处理多个并发的请求。这些都是多线程的应用

进程与线程比较:
1.与进程相比较,线程更加“轻量级”,创建、撤销一个线程比启动、撤销一个进程开销要小的多。一个进程中的所有线程共享此进程的所有资源
2.没有进程就没有线程,进程一旦终止,其内的线程也将不复存在
3.进程是操作系统资源调度的基本单位。进程可以独享资源;线程需要依托进程提供的资源,无法独立申请操作系统资源,是OS任务执行的基本单位。

线程状态

在这里插入图片描述

Java多线程实现

继承Thread类实现多线程

java.lang.Thread是一个线程操作的核心类。新建一个线程简单的方法就是直接继承Thread类,而后覆写该类中的 run()方法(就相当于主类中的main方法)

定义线程的主体类

class MyThread extends Thread{//线程主体类
    private String title;
    public MyThread(String title){
        this.title = title;
    }

    @Override
    public void run(){//所有线程从此处开始执行
        for(int i = 0; i < 10; i++){
            System.out.println(this.title + ",i = " + i);
        }
    }
}

当现在有了线程的主体类之后,很自然我们就会想到产生线程类的实例化对象而后调用run()方法。
观察调用run()方法

public class Test{
    public static void main(String[] args){
        MyThread myThread1 = new MyThread("abaka");
        MyThread myThread2 = new MyThread("abaka1");
        MyThread myThread3 = new MyThread("abaka2");
        myThread1.run();
        myThread2.run();
        myThread3.run();
    }
}

运行结果:

abaka,i = 0
abaka,i = 1
abaka,i = 2
abaka,i = 3
abaka,i = 4
abaka,i = 5
abaka,i = 6
abaka,i = 7
abaka,i = 8
abaka,i = 9
abaka1,i = 0
abaka1,i = 1
abaka1,i = 2
abaka1,i = 3
abaka1,i = 4
abaka1,i = 5
abaka1,i = 6
abaka1,i = 7
abaka1,i = 8
abaka1,i = 9
abaka2,i = 0
abaka2,i = 1
abaka2,i = 2
abaka2,i = 3
abaka2,i = 4
abaka2,i = 5
abaka2,i = 6
abaka2,i = 7
abaka2,i = 8
abaka2,i = 9

这个时候只是做了一个顺序打印,和多线程一点关系都没有。正确启动多线程的方式是调用Thread类中的start()方 法。

启动多线程:public synchronized void start()此方法会自动调用线程的run()方法

正确启动多线程

扫描二维码关注公众号,回复: 4891436 查看本文章
public class Test{
    public static void main(String[] args){
        MyThread myThread = new MyThread("abaka");
        MyThread myThread1 = new MyThread("abaka1");
        MyThread myThread2 = new MyThread("abaka2");
        myThread.start();
        myThread1.start();
        myThread2.start();
    }
}

此时再次执行代码发现,所有的线程对象变味了交替执行。

无论那种方法实现多线程,线程启动一定调用Thread类提供的start()方法!

线程的start方法只能调用一次,多次调用会java.lang.IllegalThreadStateException

Java线程创建路径:
start(Java方法) -> strat0(JVM) -> 进行资源调度,系统分配(JVM) -> run(java方法)执行线程的具体操作任务

Runnable()接口实现多线程

Thread类的核心功能是进行线程的启动。如果一个类为了实现多线程直接去继承Thread类就会有但继承局限。在 java中又提供有另外一种实现模式:Runnable接口。

Runnable接口:

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

利用Runable接口实现线程主体类

class MyThread implements Runnable{
    private String title;
    public MyThread(String title){
        this.title = title;
    }

    @Override
    public void run(){
        for(int i = 0; i < 5; i++){
            System.out.println(this.title + ",i = " + i);
        }
    }
}

此时MyThread类继承的不再是Thread类而实现了Runnable接口,虽然解决了单继 承局限问题,但是没有start()方法被继承了。那么此时就需要关注Thread类提供的构造方法。
Thread类提供的构造方法

public Thread(Runnable target)
可以接收Runnable接口对象

启动多线程

public class Test{
    public static void main(String[] args){
        MyThread myThread = new MyThread("abaka");
        MyThread myThread1 = new MyThread("abaka1");
        MyThread myThread2 = new MyThread("abaka2");
        new Thread(myThread).start();
        new Thread(myThread1).start();
        new Thread(myThread2).start();

         }
}

多线程的启动永远都是Thread类的start()方法

对于此时的Runnable接口对象可以采用匿名内部类或者Lambda表达式来定义。

使用匿名内部类进行Runnable对象创建

public class Test{
    public static void main(String[] args){
          new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello abaka");
            }
        }).start();
    }
}

使用Lamdba表达式进行Runnable对象创建

    public static void main(String[] args){
       nnable runnable = () -> System.out.println("hello abaka");
        new Thread(runnable).start();
    }
}

继承Thread类与实现Runnable接口的区别
I.Thread类与自定义线程类(实现了Runnable接口)。是一个典型的代理设计模式。Thread类负责辅助真实业务操作(资源调度,创建线程并启动)自定义线程类负责真实业务的实现(run方法具体要做啥事)
II.使用Runnable接口实现的多线程程序类可以更好的描述共享的概念

使用Thread实现数据共享(产生若干线程进行同一数据的处理操作)

class MyThread extends Thread{
    private int ticket = 5;
    @Override
    public void run(){
        while(this.ticket > 0){
            System.out.println("剩余票数:" + this.ticket -- );
        }
    }
}

public class Test{
    public static void main(String[] args){
        new MyThread().start();
        new MyThread().start();
        new MyThread().start();
    }
}

此时启动三个线程实现卖票处理。结果变为了卖各自的票

使用Runnable实现共享

class MyThread implements Runnable{
    private int ticket = 5;
    @Override
    public void run(){
        while(this.ticket > 0){
            System.out.println("剩余票数: " + this.ticket -- );
        }
    }
}
public class Test{
    public static void main(String[] args){
        MyThread myThread = new MyThread();
        new Thread(myThread).start();
        new Thread(myThread).start();
    }
}

运行结果:

剩余票数: 5
剩余票数: 4
剩余票数: 3
剩余票数: 2
剩余票数: 1

Runnable实现的多线程的程序类可以更好的描述出程序共享的概念

Callable实现多线程

从JDK1.5开始追加了新的开发包:java.uti.concurrent。这个开发包主要是进行高并发编程使用的,包含很多在高并 发操作中会使用的类。在这个包里定义有一个新的接口Callable

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

Runnable中的run()方法没有返回值,它的设计也遵循了主方法的设计原则:线程开始了就别回头。但是很多时候需 要一些返回值,例如某些线程执行完成后可能带来一些返回结果,这种情况下就只能利用Callable来实现多线程。
使用Callable定义线程主体类。

class MyThread implements Callable<String> {

    private int ticket = 5;
    @Override
    public String call() throws Exception{
        while(this.ticket > 0){
            System.out.println("剩余票数:" + this.ticket --);
        }
        return "票卖完";
    }
}

启动并取得多线程的执行结果

public class Test{
    public static void main(String[] args) throws InterruptedException, ExecutionException{
        FutureTask<String> task = new FutureTask<>(new MyThread());
        new Thread(task).start();
        new Thread(task).start();
        System.out.println(task.get());
    }
}

其中FutureTask task = new FutureTask<>(new MyThread());这句是因为callable的继承关系如下图:
其中箭头表示继承关系。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_39032310/article/details/83904776