Java之多线程

进程、线程介绍

进程>线程,一个进程中可以有i

在一个进程中如果有多个线程,那么线程(cpu执行和调度的单位)是交替进行的,这是被模拟出来的,因为只有一个cpu只能处理一个线程,快速切换使我们看着是同时进行的

真正的多线程是拥有多个cpu就可以实现真正的同时进行

有以下几点需要我们注意:

1.线程就是独立执行的路径

2.程序执行时即使没有创建线程,后台也有多个线程,如:主线程,gc线程

3.mian()称为主线程,是系统的入口,用于执行整个程序

4.对同一份资源进行操作时,会出现资源抢夺的问题,需要加入并发控制

5.线程会增加消耗,比如时间,cpu调度时间的消耗

6.每个线程在自己工作内存交互,内存控制不当会导致数据不一致


线程的创建

继承Thread类

在需要创建线程的类继承Thread,继承后必须重写run()方法

public class demo extends Thread{
    public void run(){
        for (int i = 0; i < 20; i++) {
            System.out.println("我在吃饭 "+i);
        }
    }

    public static void main(String[] args) {
        demo thread = new demo();
        thread.start();
        for (int i = 0; i < 20; i++) {
            System.out.println("我正在看书 "+i);
        }
    }
}

交替速度与电脑cpu有关,调用start方法多线程执行

创建线程:类名        引用变量 = new        类名();


网图下载

利用工具包commons-io编写程序下载网图

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

public class demo2 extends Thread{
    private String url;
    private String name;

    public demo2(String url,String name){
        this.url = url;
        this.name = name;
    }

    public void run(){
        WebDownLoader webDownloader = new WebDownLoader();
        webDownloader.downloader(url,name);
        System.out.println("下载了文件名为"+name);
    }

    public static void main(String[] args) {
        demo2 thedemo1 = new demo2("https://i1.hdslb.com/bfs/archive/75b12ea49e8d7cc6cd2d0ada331f9851fe5ad27c.jpg@672w_378h_1c_!web-search-common-cover.webp","1.jpg");
        demo2 thedemo2 = new demo2("https://i1.hdslb.com/bfs/archive/c9958e7a5a8553c1a93aa1787ef5847e06748650.jpg@672w_378h_1c_!web-search-common-cover.webp","2.jpg");
        demo2 thedemo3 = new demo2("https://i1.hdslb.com/bfs/archive/41575b1afec5305fa329d1cdf853373955d4e62a.jpg@672w_378h_1c_!web-search-common-cover.webp","3.jpg");

        thedemo1.start();
        thedemo2.start();
        thedemo3.start();
    }
}

class WebDownLoader{
    //下载方法
    public void downloader(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常,downloader方法出行问题");
        }
    }
}

Runnable接口

相较于Thread类,两者相差不大,多了一个代理的方式

Thread类创建:Thread thread  = new thread();

然后        thread.start();

Runnable接口:创建一个代理(类名   引用变量  =  new  类名();)

然后  new  Thread(引用变量,线程名).start();

推荐使用Runnable,Thread需要继承有单继承的局限性


初识并发问题

多个线程同时操作一个资源时会导致数据紊乱,不安全

如以下模拟抢票代码

public class demo implements Runnable{
    private int tick = 10;

    @Override
    public void run() {
        while (true){
            if (tick<=0){
                break;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName()+"拿到了第"+(tick--)+"张票");
        }
    }

    public static void main(String[] args) {
        demo thedemo = new demo();

        new Thread(thedemo,"小明").start();
        new Thread(thedemo,"陈平安").start();
        new Thread(thedemo,"黄老师").start();
    }
}

有拿到相同票的,有拿到-1张票的,数据紊乱


案列之龟兔赛跑

public class demo implements Runnable{
    private String winner;
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            if (Thread.currentThread().getName().equals("兔子")&&i%10==0){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            if (gameover(i)){
                break;
            }
            System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
        }
    }
    
    
    private boolean gameover(int steps){
        if (winner!=null){
            return true;
        }
        //编写判断是否比赛结束的方法
        {
            if(steps==100){
                winner = Thread.currentThread().getName();
                System.out.println("winner is "+winner);
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        demo thedemo = new demo();

        new Thread(thedemo,"兔子").start();
        new Thread(thedemo,"乌龟").start();
    }
}

实现Callable接口

接口Callable

然后重写call方法

 //创建执行服务
        ExecutorService ser = Executors.newFixedThreadPool(3);
        //提交执行
        Future r1 = ser.submit(thedemo1);
        Future r2 = ser.submit(thedemo2);
        Future r3 = ser.submit(thedemo3);
        //获取结果
        try {
            boolean rs1 = r1.get();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
        try {
            boolean rs2 = r2.get();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
        try {
            boolean rs3 = r3.get();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
        //关闭服务
        ser.shutdown();

总共5个步骤


静态代理

必须有一个真实对象,然后将对象放入代理类中,代理类帮助真实对象完成一些其无法完成的操作

而不干涉真实对象本身,真实对象可以做自己的事情

注意:真实对象和代理要实现同一个接口

public class demo {
    public static void main(String[] args) {
        new WeddingCompeny(new You()).happyMarry();
    }
}
interface Marray{
   void happyMarry();
}

class You implements Marray{
    @Override
    public void happyMarry() {
        System.out.println("你要结婚了,新郎不是我");
    }
}

class WeddingCompeny implements Marray{
    private Marray target;
    public WeddingCompeny(Marray target){
        this.target = target;
    }
    @Override
    public void happyMarry() {
        before();
        this.target.happyMarry();
        after();
    }

    private void after(){
        System.out.println("收款");
    }

    private void before(){
        System.out.println("布置婚礼");
    }
}

Lamda表达式

函数式接口的定义:

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

对于函数式接口可以使用Lamda表达式来创建该接口对象

本身是用于简化代码,可以由匿名内部类推导,去掉无用代码,留下核心逻辑,修饰词、返回值的类型、类名、类接口都去掉

public class demo2 {
    public static void main(String[] args) {
        Face face = ()->{
            System.out.println("you know what i mean");
        };
        face.fackbook();
    }
}

interface Face{
    void fackbook();
}

Lamda表达式还有三种简化方式

public class demo2 {
    public static void main(String[] args) {
        //1.参数类型简化
        Face face = (a)->{
            System.out.println("you know what i mean"+a);
        };
        face.fackbook(1);

        //2.简化括号
        Face face1 = a->{
            System.out.println("you know what i mean"+a);
        };
        face1.fackbook(2);

        //3.去掉花括号(代码只有一行的情况下可以去掉)
        Face face2 = a->System.out.println("you know what i mean"+a);
    }
}

interface Face{
    void fackbook(int a);
}

你可能感兴趣的:(java,开发语言)