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 (垃圾回收器),它就是一个很称职的守护者。