(18)多线程

先了解下多进程,什么是多进程什么是多线程,多进程跟多线程的关系

进程:指正在运行的程序。确切的来说,当一个程序进入内存运行,即变成一个进程,下面为三个进程

线程:进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少一个线程,也可以有多个线程

举个栗子:

多进程:比如食堂,食堂里的一个个卖馒头,卖盖饭,卖砂锅的窗口就是一个个进程,一到饭点,这些窗口同时卖饭,这叫多进程,也即是你手机上着微信也能聊QQ,还能听音乐

多线程:比如卖馒头的今天只有100个馒头,你可以排一队,也可以排两队,甚至三队,这个队就是线程,这就是多线程

简而言之:一个程序运行后至少有一个进程,也可以是多个,一个进程中至少有一个线程,也可以有多个

1.1主线程

当一个程序启动时,就有一个进程被操作系统(OS)创建,与此同时一个线程也立刻运行,该线程通常叫做程序的主线程(Main Thread),因为它是程序开始时就执行的,如果你需要再创建线程,那么创建的线程就是这个主线程的子线程,发现创建新执行线程有两种方法。

①一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。创建对象,运行线程

②另一种方法是声明一个实现 Runnable 接口的类。该类然后实现 run 方法。然后创建Runnable的子类对象,传入到某个线程的构造方法中,开启线程

1.2Thread

创建线程的步骤:

1 定义一个类继承Thread。

2 重写run方法。

3 创建子类对象,就是创建线程对象。

4 调用start方法,开启线程并让线程执行,同时还会告诉jvm去调用run方法

举个例子:

 public class doubleDemo extends Thread{

    @Override

    public void run() {

        for (int i=0;i<1000;i++)

        {

            System.out.println("i="+i);

        }

    }

}

public class Demo2 {

    public static void main(String[]args)

    {

        doubleDemo d=new doubleDemo();

        d.start();

    }

}

原理:Thread类的子类重写Run方法,只是将Run方法里的代码块启动起来,创建子类对象并start才是运行起来

可是为什么不直接创建线程Thread的对象呢,那是因为start调用的是Run方法,相当于线程没有启动就运行

1.3实现Runnable接口

创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后创建Runnable的子类对象,传入到某个线程的构造方法中,开启线程

创建线程的步骤。

1、定义类实现Runnable接口。

2、覆盖接口中的run方法。。

3、创建Thread类的对象

4、将Runnable接口的子类对象作为参数传递给Thread类的构造函数。

5、调用Thread类的start方法开启线程

public class MyRunnable implements Runnable{

    @Override

    public void run() {

        for (int i=0;i<1000;i++)

        {

            System.out.println("i="+i);

        }

    }

}

public class Demo3{

    public static void main(String[]args){

        Runnable runnable=new MyRunnable();

        Thread thread=new Thread(runnable);

        thread.start();

        for (int j=0;j<1000;j++){

            System.out.println("j="+j);

        }

    }

实现Runnable接口跟继承Thread类的区别

实现Runnable接口,避免了继承Thread类的单继承局限性。覆盖Runnable接口中的run方法,将线程任务代码定义到run方法中。但创建Thread类的对象,只有创建Thread类的对象才可以创建线程

实现Runnable的好处

第二种方式实现Runnable接口避免了单继承的局限性,所以较为常用。实现Runnable接口的方式,更加的符合面向对象,线程分为两部分,一部分线程对象,一部分线程任务。继承Thread类,线程对象和线程任务耦合在一起。一旦创建Thread类的子类对象,既是线程对象,有又有线程任务。实现runnable接口,将线程任务单独分离出来封装成对象,类型就是Runnable接口类型。Runnable接口对线程对象和线程任务进行解耦。

1.4线程池

线程池,其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源

在java中,如果每个请求到达就创建一个新线程,开销是相当大的。在实际使用中,创建和销毁线程花费的时间和消耗的系统资源都相当大,甚至可能要比在处理实际的用户请求的时间和资源要多的多。除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。如果在一个jvm里创建太多的线程,可能会使系统由于过度消耗内存或“切换过度”而导致系统资源不足。为了防止资源不足,需要采取一些办法来限制任何给定时刻处理的请求数目,尽可能减少创建和销毁线程的次数,特别是一些资源耗费比较大的线程的创建和销毁,尽量利用已有对象来进行服务

1.4.1使用线程池方式--Runnable接口

通常,线程池都是通过线程池工厂创建,再调用线程池中的方法获取线程,再通过线程去执行任务方法

Executors:线程池创建工厂类

public static ExecutorService  newFixedThreadPool(int nThreads):返回线程池对象

ExecutorService:线程池类

Futuresubmit(Runnable task):获取线程池中的某一个线程对象,并执行

Future接口:用来记录线程任务执行完毕后产生的结果。线程池创建与使用

使用线程池中线程对象的步骤:

创建线程池对象

创建Runnable接口子类对象

提交Runnable接口子类对象

关闭线程池

具体代码如下:

public class MyRunnablePool implements Runnable{

    @Override

    public void run() {

        System.out.println("同桌张杰");

        try {

            Thread.sleep(2000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

    }

}

public class MyRunnablePoolDemo {

    public static void main(String[]args){

        ExecutorService service= Executors.newFixedThreadPool(2);

        Runnable R=new MyRunnablePool();

        service.submit(R);

        service.submit(R);

        service.shutdown();

    }

}

1.4.2使用线程池方式—Callable接口

Callable接口:与Runnable接口功能相似,用来指定线程的任务。其中的call()方法,用来返回线程任务执行完毕后的结果,call方法可抛出异常。

ExecutorService:线程池类

Futuresubmit(Callable task):获取线程池中的某一个线程对象,并执行线程中的call()方法

Future接口:用来记录线程任务执行完毕后产生的结果。线程池创建与使用


使用线程池中线程对象的步骤:

创建线程池对象

创建Callable接口子类对象

提交Callable接口子类对象

关闭线程池

代码演示:

public class MyCallablePool implements Callable {

    int x;

    int y;

    public MyCallablePool(int x, int y) {

        this.x = x;

        this.y = y;

    }

    @Override

    public Integer call() throws Exception {

        return x+y;

    }

}

public static void main(String[]args){

        ExecutorService service= Executors.newFixedThreadPool(2);

        MyCallablePool myCallablePool=new MyCallablePool(100,300);

        Future future=service.submit(myCallablePool);

        try {

            Integer I=future.get();

            System.out.println(I);

        } catch (InterruptedException e) {

            e.printStackTrace();

        } catch (ExecutionException e) {

            e.printStackTrace();

        }

    }

你可能感兴趣的:((18)多线程)