🌞Java多线程

创建多线程

1. 继承Thread类

将类声明为Thread类的子类,并重写run方法,创建对象,开启线程

public class MyThread extends Thread{
      @Override
      public void run(){
            synchronized (object) {
                i++;
                System.out.println("i:"+i);
                try {
                    System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态");  
                    Thread.currentThread().sleep(10000);
                } catch (InterruptedException e) {
                    // TODO: handle exception
                }
                System.out.println("线程"+Thread.currentThread().getName()+"睡眠结束");
                i++;
                System.out.println("i:"+i);
            }
      }
}

start():启动线程,sleep():在指定的毫秒数内让正在执行的线程休眠

当执行start()之后,jvm就会开启一个新的线程并且调用run方法,当执行线程的任务结束时,线程在内存中就会释放,当所有的线程都结束时,进程就会结束。

获取相应的线程名字mythread.currentThread().getName()

  * currentThread():返回对当前正在执行的线程对象的引用
  * getName():获取该线程的名字

2. 通过实现Runnable接口

实现Runable的好处:避免了单一继承的局限性,线程分为两部分,一部分是线程对象,另一部分是线程任务,继承Thread类,线程对象和线程任务耦合在一起,一旦创建了Thread类的子类,即是线程对象,又是线程任务,实现Runnable接口,将线程任务单独分离出来封装成对象,类型就是Runnable接口类型,Runnable接口对线程对象和线程任务进行解耦。

  1. 实现Runnable接口,并重写run方法
//1.实现runnable接口并重写run方法
    class MyRunnable implements Runnable{

        @Override
        public void run() {

        }
    }
  1. 创建Runnable实例
MyRunnable runnable = new MyRunnable();
  1. 创建Thread对象
Thread thread = new Thread(runnable);
thread.start();
  1. 匿名的方法实现Runnable接口
//1.匿名实现Runnable接口并重写run方法
        Runnable runnable = new Runnable() {
            @Override
            public void run() {

            }
        };

线程池


1. 创建线程池

线程池就是一个存在多个线程的容器,其中的线程可以重复使用,省去了重复创建线程浪费的操作,节省了资源。

  1. Runnable接口方法

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

Executors:线程池创建工厂类
public static ExecutorService newFixedThreadPool(int nThread):返回线程池对象
ExecutorService:线程池类
Future接口:用来记录线程任务执行完毕后产生的后果

使用线程池的方法:

  • 创建线程池对象
  • 创建Runnable接口子类对象
  • 提交Runnable接口子类对象
  • 关闭线程池
//创建线程池对象
ExecutorService service = Executor.newFixedThreadPool(2);
MyRunnable r = new MyRunnable();

//从线程池中获取对象,调用run方法
service.submit(r);

//关闭线程池
service.shutdown();
  1. Callable接口

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

//创建线程池对象
ExecutorService service = Exectors.newFixedThreadPool(2);
MyCallable call = new MyCallable();

service.submit(call)

//创建Callable子类
public class MyCallable implements Callable {

@Override
public Object call() throws Exception {
            System.out.println("我要一个教练:call");
            Thread.sleep(2000);
            System.out.println("教练来了: " +Thread.currentThread().getName());
            System.out.println("教我游泳,交完后,教练回到了游泳池");
            return null;
      }
}

2. 等待子线程结束

有时候我们的主线程需要等子线程执行结束之后再开始执行。

  1. 第一种解决方法是使用全局标记
public class MyCallable implements Callable<Integer> {
    
    public static int number=20;//总任务数
    //...
}

number随便放那个类,只要static就好,

public static void main(String[] args) throws InterruptedException, ExecutionException {

        //创建线程池对象

        while(MyCallable.number!=0){
            Thread.sleep(1000);
            System.out.print("等待子线程执行...\n");
        }

        //执行结束

while循环放在主线程中,阻塞主线程,等number减为0的时候循环结束。

  1. 还有一种方法是使用插件CountDownLatch,不过没有试过,差不多也是这个原理,有阻塞主线程的功能。

线程池传参

使用的线程池是Executors,很简单,就是重写了构造方法,里面的参数在传入时尽量使用new方法重新创建,因为很可能会在第一个子线程传入参数还没有执行call的时候传参对象被第二个线程覆盖。

public class MyCallable implements Callable<Integer> {

    public static int number=20;//总任务数

    private int i = 0;//传入参数

    public MyCallable(int i){
        this.i = i;
    }


    @Override
    public Integer call() throws Exception {
        
    }
}

附Demo

Demo.java

package com.Runable;

import java.util.concurrent.Callable;

public class MyCallable implements Callable<Integer> {

    public static int number=20;//总任务数

    private int i = 0;//传入参数

    public MyCallable(int i){
        this.i = i;
    }


    @Override
    public Integer call() throws Exception {
        System.out.print("线程"+i+"!\n");
        Thread.sleep(3000);
        //System.out.print(i);
        System.out.print("线程"+i+"执行完毕!\n");
        MyCallable.number--;
            return (i%2==0?i:null);
    }
}

MyCallable.java

package com.Runable;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class Demo {


    public static void main(String[] args) throws InterruptedException, ExecutionException {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i <10; i++) {
            list.add(i);
        }

        //创建线程池对象
        ExecutorService service = Executors.newFixedThreadPool(10);
        List<Future<Integer>> futures = new ArrayList<Future<Integer>>();

        for (int i=0;i<list.size();i++){
            MyCallable myCallable = new MyCallable(list.get(i));
            futures.add(service.submit(myCallable));

        }

        while(MyCallable.number!=0){
            Thread.sleep(1000);
            System.out.print("...\n");
        }

        //执行结束
        for (Future<Integer> i:futures){
            System.out.print("获取结果"+i.get());
        }

        //关闭线程池
        service.shutdown();
    }
}

posted @ 2020-07-06 09:26  两小无猜  阅读(116)  评论(0编辑  收藏  举报