3.1 多线程

1. 继承Thread类

package com.threaddd;

// 继承Thread类:1.继承Thread类,重写run方法,调用start开启线程
//总结:注意,线程开启不一定立即执行,有cpu调度执行

public class TestThread1 extends Thread{
    //run();重写 override快捷键CTRL + O;
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 200; i++) {
            System.out.println("RUN"+i);
        }

    }

    public static void main(String[] args) {
        //main线程,主线程
        //创建一个主线程
        TestThread1 testThread1 = new TestThread1();
        //调用start()方法开启线程,而不是run
        testThread1.start();
        for (int i = 0; i < 200; i++) {
            System.out.println("我在学习多线程"+i);
        }
    }

}

2. 用线程下载网图

package  com.threaddd;

import org.apache.commons.io.FileUtils;

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

public class TestThread2 extends Thread {
    private String url;
    private String name;
    //构造器
    public TestThread2(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) {
        TestThread2 t1 = new TestThread2("https://img2020.cnblogs.com/blog/1883993/202102/1883993-20210228172150715-1170074631.png","1");
        TestThread2 t2 = new TestThread2("https://img2020.cnblogs.com/blog/1883993/202102/1883993-20210228172150715-1170074631.png","2");
        TestThread2 t3 = new TestThread2("https://img2020.cnblogs.com/blog/1883993/202102/1883993-20210228172150715-1170074631.png","3");
        t1.start();
        t2.start();
        t3.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方法出现问题");

        }
    }
}

3. 实现Run able接口

  • 定义MyRunable类实现RunAble接口
  • 实现run()方法,编写线程执行体
  • 创建线程对象,调用Start()方法启动

推荐使用Runable对象,由于Java单继承的局限

总结:

  • 继承Thread

    • 子类继承Thread类具备多线程能力
    • 启动线程:子类对象.start()
    • 不建议使用:避免OOP单继承的局限性
  • 实现runable接口具有多线程的能力

    • 启动线程:传入目标对象+Thread对象.start
    • 推荐使用:避免单继承的局限性,灵活方面,方便一个对象被多个线程使用。

例题:火车票

package com.threaddd;
//多个线程同时操作一个同一个对象
//买火车票的例子
public class TrainTicket implements Runnable{
    private int tickets = 10;
    @Override
    public void run() {
        while (true){
            if(tickets <= 0)
                break;
        }
        //模拟延时
        try{
            Thread.sleep(200);//单位,毫秒
        }catch (InterruptedException e){//当阻塞方法收到中断请求的时候就会抛出InterruptedException异常
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"-->拿到了第"+tickets--+"票");
    }

    public static void main(String[] args) {
        //发现问题,多个线程操作同一个资源,线程不安全,数据紊乱
        TrainTicket trainTicket = new TrainTicket();
        new Thread(trainTicket,"小明").start();
        new Thread(trainTicket,"老师").start();
        new Thread(trainTicket,"黄牛").start();
    }
}

例题:龟兔赛跑跑

package com.threaddd;
//龟兔赛跑 rabbit tortoise
public class Race implements Runnable{
    //一个胜利者
    private static String winner ;
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            //模拟兔子睡觉
            if(Thread.currentThread().getName().equals("R") && i % 10 ==  0)
                try{
                    Thread.sleep(1);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }

            //判断比赛是否结束,是的话就跳出
            if(gameOver(i)){
                break;
            }
            System.out.println(Thread.currentThread().getName()+"跑了第"+i+"步");
        }
    }

    private boolean gameOver (int step){
        if (winner != null)
            return true;
        else if (step >= 100){
            winner = Thread.currentThread().getName();
            System.out.println("The winner is "+winner);
            return  true;
        }else
        return false;
    }

    public static void main(String[] args) {
        Race race = new Race();
        new Thread(race,"R").start();
        new Thread(race,"tortoise").start();
    }
}

4. Callable 接口

创建线程方法3:实现Callable接口

  • 实现Callable接口需要返回值类型
  • 重写Call方法,需要抛出异常
  • 创建目标对象
  • 创建执行服务:ExecutorService ser = Executor.newFixedThreadPool(1);
  • 提交执行:Future<boolean r1 = result1.get()
  • 关闭服务:ser.shutdownNow();

5. 静态代理模式

线程的底部实现原理

总结:

  1. 这是对象和代理对象都要实现同一个接口
  2. 代理对象要代理真实角色

好处:

  1. 代理对象可以做很多正式对象做不了的事
  2. 真实对象专注做自己的事
package com.threaddd.staticproxy;

import sun.plugin2.main.client.WDonatePrivilege;

public class StaticProxy {
    public static void main(String[] args) {
        WeddingCompany weddingCompany = new WeddingCompany(new You());//可以直接再这里new You()
        weddingCompany.happyMarry();
        /*
        假如不用代理
        You you = new You();
        You.happyMarry();
        这样每一个人的婚礼都一模一样。用了代理可以真实对象最出更多自己专属的动作
         */
        //与多线程的联系
        /*
            You you = new You();
        new Thread(new Runnable() { //lambda表达式?
            @Override
            public void run() {
                System.out.println("I love You");
            }
        }).start();
        new WeddingCompany(new You()).happyMarry();
        //上面一行等价于
        /*
            WeddingCompany weddingCompany1 = new WeddingCompany(you);
             weddingCompany1.happyMarry();
         */

         */

    }
}

interface Marry{
    void happyMarry();
}

class You implements Marry{

    @Override
    public void happyMarry() {
        System.out.println("要结婚了,超开心");
    }
}
//WeddingCompany
class WeddingCompany implements Marry{
    private Marry target;
    //new默认是调用无参构造方法,婚庆公司这里的构造方法需要传入Marry类的的一个target
    public WeddingCompany(Marry target){
        this.target= target;
    }

    @Override
    public void happyMarry() {
        before();
        this.target.happyMarry();
        after();
    }
    private void before() {
        System.out.println("结婚之前,不知场所");
    }

    private void after() {
        System.out.println("结婚之后,统计份子");
    }


}
posted @ 2021-03-22 21:09  诸葛蛋蛋  阅读(39)  评论(0)    收藏  举报