多线程和Lambda表达式入门


什么是线程

进程:一个进程包括有操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有分守护线程都结束后才能结束。多线程能满足程序员编写高效率的程序来达到充分利用CPU的目的。

一个线程的生命周期

线程是一个动态执行的过程,它有一个从产生到死亡的过程。

java lambda写线程_经验分享

  • 新建状态:

    使用new 关键字和Thread类或其子类建立一个线程对象后,该项成对象就处于新建状态。它保持这个状态直到程序start()这个线程。

  • 就绪状态:

    当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要登台JVM里线程调度器的调度。

  • 运行状态:

    如果就绪状态的线程获取CPU资源,就可以执行run(),此时线程变处于运行状态了。处于运行状态的线程最为复杂,它可以编程阻塞状态、就绪状态和死亡状态。

  • 阻塞状态:

    如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:

    • 等待阻塞:运行状态中的线程执行wait()方法,使线程进入到登台阻塞状态。

    • 同步阻塞:线程在获取synchronized同步锁失败(因为同步锁被其他线程占用)。

    • 其他阻塞:通过调用线程的sleep()或join()发出了I/O请求时,线程就会进入阻塞状态。当sleep()状态超时,join()等待线程终止或超时,获取I/O处理完毕,线程重新转入就绪状态。

  • 死亡状态:

    一个运行状态的线程完成任务或者其他终止条件发生时,该线程就会切换到终止状态。

线程的优先级

每一个Java线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。

Java线程的优先级是一个整数,其取值范围是1(Thread.MIN_PRIORITY)-10(Thread.MAM_PRIORITY)。默认情况下,每一个线程都会分配一个优先线程NORM_PRIORITY(5)。

具有较高优先级的线程对程序更重要,并且应该在低优先级的县城之前分配处理器资源。但是,线程优先级不能保证线程执行的顺序,儿啊且非常依赖于平台。

创建一个线程

  • 通过继承Thread类本身

  • 通过实现Runable接口

  • 通过实现Callable和Future创建线程

①:继承java.lang.Thread类, 重写run()方法

创建一个线程的第一种方法是创建一个新的类,该类继承Thread类,然后创建一个该类的实例。

继承类必须重写run()方法,该方法是新县城的入口点。他必须调用start()方法才能执行。

该方法尽管被列为了一种多线程的实现方式,但是本质上也是实现了Runnable接口的一个实例。

package com.kkb.spring.hello.helleThread.test;
//创建线程方式:继承Thread类,重写run()方法,调用start开启线程

//总结:线程开启不一定立即执行,由CPU调度执行

public class TestThread extends  Thread{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("我在看代码"+i);
        }
    }

    public static void main(String[] args) {
        //创建一个线程对象
        TestThread testThread=new TestThread();
        //调用start()方法
        testThread.start();
        for (int i = 0; i < 20; i++) {
            System.out.println("我在学习多线程"+i);
        }
    }
}

②:实现Runable接口,重写run()方法然后使用Thread类来包装

package com.kkb.spring.hello.helleThread.test;
//通过实现runnable接口创建线程
public class TestThread3 implements Runnable{

    public static void main(String[] args) {

        TestThread3 testThread3=new TestThread3();
        new Thread(testThread3).start();
        for (int i = 0; i < 20; i++) {
            System.out.println("我在看代码"+i);
        }
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("我在学习多线程"+i);
        }
    }
}




这两种方式都是围绕着Thread和Runable,继承Thread类把run()方法写到类中,实现Runable接口是把run()方法写到接口中,然后再用Thread类来包装,两种方式都是调用了Thread类的start()方法来启动线程的。

两者在本质上没有明显的区别,只是在外观上有很大的区别,第一种方法是继承Thread类,由于java是单继承,如果继承了Thread类,就没办法继承其它的类了,在继承上有点受制,不灵活。第二种方法就是为了解决第一种单继承不灵活的问题。所以平常使用就使用第二种方法。

其他变体写法:

public static void main(String[] args) {
    //new MyThread().start();
    //new Thread(new MyRunable()).start();
    //匿名内部类
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"\t"+Thread.currentThread().getId());
        }
    }).start
    //尾部代码块,是对内部匿名类形式的语法糖
    new Thread(){
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"\t"+Thread.currentThread().getId());

        }
    }.start();

    //Runnable是函数式接口,所以可以使用Lamda表达式
    Runnable runnable=()->{
        System.out.println(Thread.currentThread().getName()+"\t"+Thread.currentThread().getId());

    };
    new Thread(runnable).start();
}

③:实现Callable接口,重写call()方法,然后包装成java.util.concurrent.FutureTask,再然后包装成Thread callable:有返回值的线程,能取消线程,可以判断线程是否执行完毕。

package com.kkb.spring.hello.helleThread.test;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

//线程创建方式3:实现callabile接口
public class TestCallable implements Callable {
    private String url;//图片地址
    private String name;//文件名称

    public TestCallable(String url, String name) {
        this.url = url;
        this.name = name;
    }
    @Override
    public Boolean call() throws Exception {
        WebDownloader1 webDownloader=new WebDownloader1();
        webDownloader.doenloader(url,name);
        System.out.println("下载了文件名为:"+name);
        return true;
    }


    public static void main(String[] args) {
        TestCallable t1=new TestCallable("https://img.kaikeba.com/736161901202lzci.png?imageMogr2/quality/85/format/webp","1.JPG");
        TestCallable t2=new TestCallable("https://img.kaikeba.com/411121111202oauc.jpg?imageMogr2/quality/85/format/webp","2.JPG");
        TestCallable t3=new TestCallable("https://img.kaikeba.com/742160111202ryal.jpg?imageMogr2/quality/85/format/webp","3.JPG");
        //创建执行服务
        ExecutorService service= Executors.newFixedThreadPool(3);
        //执行提交
        Future<Boolean> s2 = service.submit(t1);
        Future<Boolean> s1 = service.submit(t2);
        Future<Boolean> s3 = service.submit(t3);
        //获取结果

        try {
            Boolean r2 = s2.get();
            Boolean r3 = s1.get();
            Boolean r1 = s3.get();
            System.out.println(r1);
            System.out.println(r2);
            System.out.println(r3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        //关闭服务
        service.shutdown();
    }


}
class WebDownloader1{
    public  void doenloader(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常,doenloader方法出现问题");
        }
    }
}

静态代理


你:真实角色

婚庆公司:代理你,帮助你处理结婚的事

结婚:两个角色都实现结婚接口

package com.kkb.spring.hello.helleThread.test;
//静态代理模式
//真是对象和代理对象都要实现同一个接口
//代理对象要代理真是角色
//代理对象可以做很多真实对象做不了的事情
//真是对象专注于做自己的事情
public class StaticProxy {
    public static void main(String[] args) {
        You you=new You();//你要结婚
        new Thread(()-> System.out.println("i love you")).getName();
        new WeddingCompany(new You()).happyMarry();
        WeddingCompany weddingCompany=new WeddingCompany(new You());
        weddingCompany.happyMarry();
    }
}
//结婚接口
interface Marry{
    void happyMarry();
}

//真实角色
class You implements Marry{

    @Override
    public void happyMarry() {
        System.out.println("小明要结婚了,超开心");
    }
}

//代理角色,帮助小明结婚
class WeddingCompany implements Marry{
    //代理谁-->真实目标角色
    private Marry target;

    public WeddingCompany(Marry target) {
        this.target = target;
    }

    @Override
    public void happyMarry() {
        befor();
        this.target.happyMarry();//这个是真实对象
        after();
    }

    private void after() {
        System.out.println("结婚之后收尾款");
    }

    private void befor() {

        System.out.println("结婚之前,布置婚礼现场");
    }

}


Lamda表达式


Lambda 表达式是 JDK8 的一个新特性,可以取代大部分的匿名内部类,写出更优雅的 Java 代码,尤其在集合的遍历和其他集合操作中,可以极大地优化代码结构。

  • λ希腊字母表中排序第是一位的字母,英语名称为Lambda
  • 避免匿名内部类定义过多
  • 其实质属于函数式编程的概念

为什么使用lambda表达式

  • 避免匿名内部类定义过多
  • 可以让你的代码看起来很简洁
  • 去掉了一堆没有意义的代码,只留下了核心的逻辑

FunctionalInterface(函数式接口)

任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口。

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

对于函数式接口,我们可以通过lambda表达式来创建接口对象。

package com.kkb.spring.hello.helleThread.lamda;

/**
 * 推到lambda表达式
 */
public class TestLambda {
    //3、静态内部类
    static class Like2 implements ILike{

        @Override
        public void lambda() {
            System.out.println("i like lambda2");
        }
    }
    public static void main(String[] args) {
        ILike like=new Like();
        like.lambda();
        Like2 like2 = new Like2();
        like2.lambda();

        //4、局部内部类
        class Like3 implements ILike{

            @Override
            public void lambda() {
                System.out.println("i like lambda3");
            }
        }
        Like3 like3 = new Like3();
        like3.lambda();
        //5、匿名内部类
        like=new ILike(){

            @Override
            public void lambda() {
                System.out.println("i like lambda4");
            }
        };
        like.lambda();

        //6、用lambad简化
        like=()->{
            System.out.println("i like lambda5");
        };
        like.lambda();
    }
}
//1、定义一个函数式接口
interface  ILike{
    void lambda();
}
//2、实现接口
class Like implements ILike{

    @Override
    public void lambda() {
        System.out.println("i like lambda");
    }
}