多线程学习记录

1.程序、进程、多线程

程序是程序,进程是进程,进程指的是程序的运行过程(抽象)
一个进程有多个线程,main函数就是一个主线程
进程一般由程序、数据集、进程控制块三部分组成。

2.同步和异步(消息队列)

在这里插入图片描述

3.有了进程为啥还需要线程

进程的创建非常消耗资源
进程之间独立的空间,没办法共享资源
进程间通信不方便
默认都会有一个主控制线程

进程比坐火车,线程比作车厢
进程比作工厂,线程比作工人

进程是最小的资源单位,线程是最小的执行单位

4.创建多线程

public class TryConcurrency02 {

    public static void main(String[] args) {
        // JDK 1.8 之前匿名内部类
        Thread t = new Thread("BrowseNews") {
            @Override
            public void run() {
                browseNews();
            }
        };
        t.start();

        // JDK 1.8 Lambda 编码方式
        // new Thread(TryConcurrency02::browseNews).start();
        enjoyMusic();
    }

    // 浏览新闻
    private static void browseNews() {
        while (true) {
            System.out.println("The good news.");
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    // 欣赏音乐
    private static void enjoyMusic() {
        while (true) {
            System.out.println("The nice music.");
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

使用Jconsole观察线程
jps 查看端口号 jconsole 端口号

5.线程的生命周期

执行了Trend.start()线程就开始运行了吗?
不是,只是进入了就绪队列
在这里插入图片描述

6.模板方法设计模式

/**
 * 模板方法类
 */
public abstract class Cook {

    abstract void oil(); // 食用油
    abstract void egg(); // 鸡蛋
    abstract void tomato(); // 西红柿

    // 封装具体的行为:做饭
    public final void cook() {
        this.oil();
        this.egg();
        this.tomato();
    }

}
/**
 * 具体类
 */
public class Me extends Cook {

    @Override
    void oil() {
        System.out.println("自己:油放多了!");
    }
    @Override
    void egg() {
        System.out.println("自己:鸡蛋炒糊了!");
    }
    @Override
    void tomato() {
        System.out.println("自己:西红柿放多了!");
    }

}
/**
 * 具体类
 */
public class Chef extends Cook {

    @Override
    void oil() {
        System.out.println("厨师:油适量!");
    }
    @Override
    void egg() {
        System.out.println("厨师:鸡蛋适量!");
    }
    @Override
    void tomato() {
        System.out.println("厨师:西红柿适量!");
    }

}

public class TestCook {

    public static void main(String[] args) {
        new Me().cook();
        new Chef().cook();
    }

}

结果
在这里插入图片描述
钩子函数:让子类觉得是否加油

/**
 * 模板方法类
 */
public abstract class Cook {

    abstract void oil(); // 食用油

    abstract void egg(); // 鸡蛋

    abstract void tomato(); // 西红柿

    // 钩子函数:子类可以覆写,让子类决定是否添加油,默认加油
    boolean isAddOil() {
        return true;
    }

    // 封装具体的行为:做饭
    public final void cook() {
        // 如果子类决定添加,则执行添加油的方法
        if (this.isAddOil()) {
            this.oil();
        }
        this.egg();
        this.tomato();
    }

}
/**
 * 具体类
 */
public class Me extends Cook {

    private boolean isAddOilFlag = true;

    public boolean isAddOilFlag() {
        return isAddOilFlag;
    }

    public void setAddOilFlag(boolean addOilFlag) {
        isAddOilFlag = addOilFlag;
    }

    @Override
    boolean isAddOil() {
        return this.isAddOilFlag;
    }

    @Override
    void oil() {
        System.out.println("自己:油放多了!");
    }

    @Override
    void egg() {
        System.out.println("自己:鸡蛋炒糊了!");
    }

    @Override
    void tomato() {
        System.out.println("自己:西红柿放多了!");
    }

}

7.模拟营业厅叫号机(Trend)

/**
 * 柜台窗口
 */
public class CounterWindow extends Thread {

    // 窗口名称
    private final String windowName;

    // 最多受理 50 笔业务
    private static final int MAX = 50;

    // 起始号码
    private static int index = 1;

    public CounterWindow(String windowName) {
        this.windowName = windowName;
    }

    @Override
    public void run() {
        while (index <= MAX) {
            System.out.format("请【%d】号到【%s】办理业务\n", index++, windowName);
        }
    }

    public static void main(String[] args) {
        new CounterWindow("一号窗口").start();
        new CounterWindow("二号窗口").start();
        new CounterWindow("三号窗口").start();
        new CounterWindow("四号窗口").start();
    }

}

线程创建的方式有几种?
	只有一种方式只有Trend
	实现线程执行单元的方式有两种,1.继承Trend,重写run()方法,  2.Runable

8.策略设计模式

/**
 * 旅行策略接口
 */
public interface TravelStrategy {

    // 旅行算法
    void travelAlgorithm();

}

/**
 * 具体策略类 汽车
 */
public class CarStrategy implements TravelStrategy {

    /**
     * 算法具体实现
     */
    @Override
    public void travelAlgorithm() {
        System.out.println("坐汽车...");
    }

}
/**
 * 具体策略类 火车
 */
public class TrainStrategy implements TravelStrategy {

    /**
     * 算法具体实现
     */
    @Override
    public void travelAlgorithm() {
        System.out.println("坐火车...");
    }

}

/**
 * 具体策略类 飞机
 */
public class PlaneStrategy implements TravelStrategy {

    /**
     * 算法具体实现
     */
    @Override
    public void travelAlgorithm() {
        System.out.println("坐飞机...");
    }

}
/**
 * 环境类 旅行者
 */
public class Traveler {

    // 维护策略接口对象的一个引用
    private TravelStrategy travelStrategy;

    // 通过 set 方法设置旅行策略
    public void setTravelStrategy(TravelStrategy travelStrategy) {
        this.travelStrategy = travelStrategy;
    }

    // 调用对应策略的实现
    public void travelStyle() {
        travelStrategy.travelAlgorithm();
    }

    public static void main(String[] args) {
        Traveler traveler = new Traveler();
        // 设置旅行策略
        // traveler.setTravelStrategy(new CarStrategy());
        // traveler.setTravelStrategy(new TrainStrategy());
        traveler.setTravelStrategy(new PlaneStrategy());
        traveler.travelStyle();
    }

}

9.模拟营业厅叫号机(Runable)

/**
 * 具体策略类 叫号机
 */
public class CounterWindowRunnable implements Runnable {

    // 最多受理 50 笔业务
    private static final int MAX = 50;

    // 起始号码,不做 static 修饰
    private int index = 1;

    @Override
    public void run() {
        while (index <= MAX) {
            System.out.format("请【%d】号到【%s】办理业务\n", index++, Thread.currentThread().getName());
        }
    }

    public static void main(String[] args) {
        final CounterWindowRunnable task = new CounterWindowRunnable();
        new Thread(task, "一号窗口").start();
        new Thread(task, "二号窗口").start();
        new Thread(task, "三号窗口").start();
        new Thread(task, "四号窗口").start();
    }

}

10.守护线程

在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程)
任何一个守护线程都是整个JVM中所有非守护线程的保姆
只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。
Daemon的作用是为其他线程的运行提供便利服务,守护线程最典型的应用就是 GC (垃圾回收器),它就是一个很称职的守护者。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值