JAVA从零开始学习知识整理——day07—【线程池、lambda】

一、 等待唤醒机制
1.1 线程之间的通信:多个线程在处理一个资源,但是各自任务不同。
多个线程在处理同一个资源,并且任务不同时,需要线程通信来帮助解决线程之间对同一个变量的使用或操作。就是多个线程在操作同一份数据时, 避免对同一共享变量的争夺。也就是我们需要通过一定的手段使各个线程有效的利用资源。而这种手段即—— 等待唤醒机制
1.2 等待唤醒机制
就是在一个线程进行了规定操作后,就进入等待状态(wait()), 等待其他线程执行完他们的指定代码过后再将其唤醒(notify());在有多个线程进行等待时, 如果需要,可以使用 notifyAll()来唤醒所有的等待线程。
注意事项:
1. wait方法与notify方法必须要由同一个锁对象调用。因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程。
2. wait方法与notify方法是属于Object类的方法的。因为:锁对象可以是任意对象,而任意对象的所属类都是继承了Object类的。
3. wait方法与notify方法必须要在同步代码块或者是同步函数中使用。因为:必须要通过锁对象调用这2个方法。
1.3 实例 — 消费者与店铺消费包子资源

包子资源类:(个人习惯无论什么类都写满构造方法 ---- hhh)

public class BaoZi {
    private String pi;
    private String xian;
    boolean Yn = false;

    public BaoZi(String pi, String xian, boolean yn) {
        this.pi = pi;
        this.xian = xian;
        Yn = yn;
    }

    public BaoZi() {
    }

    public String getPi() {
        return pi;
    }

    public void setPi(String pi) {
        this.pi = pi;
    }

    public String getXian() {
        return xian;
    }

    public void setXian(String xian) {
        this.xian = xian;
    }

    public boolean isYn() {
        return Yn;
    }

    public void setYn(boolean yn) {
        Yn = yn;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        BaoZi baoZi = (BaoZi) o;
        return Yn == baoZi.Yn &&
                Objects.equals(pi, baoZi.pi) &&
                Objects.equals(xian, baoZi.xian);
    }

    @Override
    public int hashCode() {

        return Objects.hash(pi, xian, Yn);
    }

    @Override
    public String toString() {
        return "BaoZi{" +
                "pi='" + pi + '\'' +
                ", xian='" + xian + '\'' +
                ", Yn=" + Yn +
                '}';
    }
}

店铺类:

 public class Store implements Runnable {

    Random rd = new Random();
    private BaoZi b;
   public Store(BaoZi b) {
        this.b = b;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (b) {
                if (b.Yn == true) {
                    try {
                        b.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if (b.Yn == false) {
                    System.out.println("包子铺开始做包子......");
                    int bz = rd.nextInt(2);
                    if (bz == 0) {
                        b.setPi("薄皮");
                        b.setXian("水晶虾仁馅");

                    } else {
                        b.setPi("厚皮");
                        b.setXian("菠萝香蕉馅");
                    }
                }
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(b.getPi() + b.getXian() + "包子做好了。");
                b.Yn = true;
                b.notify();
            }
        }
    }
}

消费者类:

public class Customer implements Runnable {
    private BaoZi b;

    public Customer(BaoZi b) {
        this.b = b;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (b) {
                if (b.Yn == false) {
                    System.out.println("告诉包子铺做包子。");
                    try {
                        b.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if (b.Yn == true) {
                    System.out.println("开始吃包子......");
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("包子吃完了");

                }
                b.Yn = false;
                b.notify();
            }

        }
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        BaoZi b = new BaoZi();

        Store s = new Store(b);
        Thread th1 = new Thread(s);

        Customer p = new Customer(b);
        Thread th2 = new Thread(p);

        th2.start();
        th1.start();
        
    }
}

二、线程池
线程池:其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。
合理利用线程池的有点:
1. 降低资源消耗。减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
2. 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
3. 提高线程的可管理性。可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多 的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。
如何创建并使用一个线程池:
1.创建线程池对象。
2.创建Runnable实现类
3.提交Runnable接口自类对象。
创建实现类:

public class MyRunnable implements Runnable {
	@Override
	public void run() {
			System.out.println("我要一个教练");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("教练来了: " + Thread.currentThread().getName());
		System.out.println("教我游泳,交完后,教练回到了游泳池");
	}
}

测试类:

public class ThreadPoolDemo {
public static void main(String[] args) { 
		ExcutorService es = Excutors.newFixedThreadPool(2);
		MyRunnable r = new MyRunnable();
		es.submit(r);

		使用lambda:
		es.submit(() ->  System.out.println("开启新的线程池。") );
}

三、 Lambda表达式
函数式编程思想:强调做什么,而不是怎么做、让谁做,重视结果,不重视过程。

3.1 冗余的Runnable代码
因为要覆盖重写run方法,其中的方法名称方法参数方法返回值都要再写一遍,除了方法体,其余都是多余的。

3.2 使用lambda表达式进行优化:
标准格式:(参数类型 参数名称)->{ 代码语句 }

3.3 无参无返回值的lambda表达式
给定一个厨子 Cook 接口,内含唯一的抽象方法 makeFood ,且无参数、无返回值。如下:
invokeFood(()-> System.out.println(“吃饭啦!”));
调用invokeFood方法,传入Cook接口,调用makefood方法。

3.4 有参数有返回值
如定义一个Person类,然后根据年龄排序;

public class Demo07ComparatorLambda {
		public static void main(String[] args) {
			Person[] array = {
				new Person("古力娜扎", 19),
				new Person("迪丽热巴", 18),
				new Person("马尔扎哈", 20) };
			Arrays.sort(array, (a,b) ‐> return a.getAge() ‐ b.getAge());  //省略写法
			for (Person person : array) {
				System.out.println(person);
		}
	}
}

3.5 有参数有返回值
给定一个计算器 Calculator 接口,内含抽象方法 calc 可以将两个int数字相加得到和值:
创建一个接口含抽象方法:
int sum(int a,int b)
测试类:
调用一个方法:
method(c,d,(a.b) -> a+b );

public int method(a,b,Calculator c){
return a+b;
}

3.6 省略格式
在Lambda标准格式的基础上,使用省略写法的规则为:

  1. 小括号内参数的类型可以省略;
  2. 如果小括号内有且仅有一个参,则小括号可以省略;
  3. 如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。
    注意:以上三个要省略需要一起省略。
    Lambda的语法非常简洁,完全没有面向对象复杂的束缚。但是使用时有几个问题需要特别注意:
  4. 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法。无论是JDK内置的 Runnable 、Comparator 接口还是自定义的接口,只有当接口中的抽象方法存在且唯一时,才可以使用Lambda。
  5. 使用Lambda必须具有上下文推断。也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。

猜你喜欢

转载自blog.csdn.net/weixin_44167508/article/details/85343938
今日推荐