等待和唤醒机制
线程间的通信,多个线程处理同一资源
多线程在并发执行时,CPU是随机切换的,我们需要让他有规律的执行
多个线程的协调通信,以此来达到共同操作统一资源,避免对同一变量的争夺。
生产者与消费者之间的关系
多个线程之间的协作机制:
资源类,属性
================
/*
* 包子类:
* 资源类
* 设置包子属性
* 皮
* 馅
* 包子的状态: true 有 | false 没有
*
*
*/
public class BaoZi {
//皮
String pi;
//馅
String xian;
//包子的状态
boolean flag = false;
}
------------------------------
/*
* 包子铺类:
* true 有包子
* false 没有
*
* 必须使用同步技术保证只有一个在执行,不能抢夺资源
* 使用包子对象作为锁对象
* 包子铺类和吃货类需要把包子对象作为参数传进来
* 在成员位置定义一个包子变量
* 使用带参构造方法,为这个包子变量赋值
*
*/
public class BaoZiPu extends Thread{
//定义一个包子
//这是一个线程类可以继承自Thread
private BaoZi bz;
public BaoZiPu() {
super();
}
public BaoZiPu(BaoZi bz) {
super();
this.bz = bz;
}
//设置线程任务,生产包子
@Override
public void run() {
int count = 0;
while(true){
synchronized (bz) {
//对包子状态进行判断
if(bz.flag=true){
try {
bz.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//被唤醒之后执行,包子铺生产包子,交替生产两种包子
if(count%2==0){
//生产猪肉大葱
bz.pi = "薄皮";
bz.xian = "猪肉大葱";
}else{
//生产冰皮 ,三鲜
bz.pi = "冰皮";
bz.xian = "三鲜";
}
count++;
System.out.println("包子铺正在生产"+bz.pi+bz.xian+"的包子");
//生产需要3秒
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//生产好之后,包子状态为有
bz.flag=true;
//唤醒吃货线程
bz.notify();
System.out.println("包子已经做好");
}
}
}
}
--------------------------------
/*
* 消费者类:
* 吃货类
*
*/
public class ChiHuo extends Thread{
private BaoZi bz;
public ChiHuo(BaoZi bz){
this.bz=bz;
}
@Override
public void run() {
//死循环,让吃货一直吃包子
while(true){
//必须同时同步技术保证两个线程只能有一个在执行
synchronized (bz) {
if(bz.flag==false){
//吃货进入等待
try {
bz.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//线程被唤醒之后执行的代码
System.out.println("吃货正在吃:"+bz.pi+bz.xian);
//吃货吃完包子
bz.flag = false;
//唤醒线程生产包子
bz.notify();
System.out.println("吃货还要吃,老板继续做");
System.out.println("----------------------------------");
}
}
}
}
----------------------------------
public class WaitAndNotify {
//测试类
public static void main(String[] args) {
//创建对象
BaoZi bz = new BaoZi();
new BaoZiPu(bz).start();
new ChiHuo(bz).start();
}
}
=======================
/*
* 定义接口
*
*/
public interface Calculator {
//计算两个int整数和的方法
public abstract int calc(int a, int b);
}
----------------------
/*
* Lambda表达式可推导可省略
* 凡是根据上下文书写出来的内容都是可以省略书写
* 可以省略的内容:
* 参数列表:括号中参数列表的类型,可以省略不写
* 括号中参数如果只有一个,那么类型和()都可以省略
* 如果大括号中的代码只有一行,无论是否有返回值,都可以省略({} return ;) 他们三个必须一起省略
* 可以推导出来的才能省略
* 使用Lambda必须具有接口
* 使用Lambda必须具有上下文推断
* 有且只有一个抽象方法的接口称之为函数式接口。
*/
public class DemoArrayList {
public static void main(String[] args) {
}
}
-----------------------
public class DemoCalcutor {
public static void main(String[] args) {
//调用
invokeCalc(10, 20, new Calculator() {
@Override
public int calc(int a, int b) {
// TODO Auto-generated method stub
return a+b;
}
});
//使用Lambds
invokeCalc(122, 130, (int a,int b)->{
return a+b;
});
//优化
invokeCalc(122, 130, ( a, b)-> a+b);
}
//定义一个方法,参数传递两个int类型的整数,参数传递接口,方法内部调用接口中的方法
public static void invokeCalc(int a, int b,Calculator c){
int sum = c.calc(a, b);
System.out.println(sum);
}
}
==================
/*
* 练习1:
* 定义一个厨子Cook接口,内含抽象方法makeFood
*
*/
public interface Cook {
//定义一个无参无返回值的方法
public abstract void makeFood();
}
----------------------------------
/*
* Lambda表达式:
* 标准格式: 一些参数 一个箭头 一段代码
* (参数) -> { 重写方法的代码 }
* ():接口中抽象方法的参数列表,没有就空着,有就写,多个参数使用逗号隔开
* ->:传递
* {}:重写接口的抽象方法的方法体
*
*
*/
public class DemoLambda {
public static void main(String[] args) {
//使用匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"创建新的线程");
}
}).start();;
//使用Lambda表达式,把括号里面的参数传到大括号里面的输出语句
new Thread(()-> {
System.out.println(Thread.currentThread().getName()+"创建新的线程");
}
).start();
//优化省略Lanbda
new Thread(()-> System.out.println(Thread.currentThread().getName()+"创建新的线程")).start();
}
}
-----------------------------
/*
* 使用实现Runable接口方式实现多线程
* 这个类有很多冗余的代码
*
*/
public class DemoRunnable {
public static void main(String[] args) {
//创建
RunnableImpl run = new RunnableImpl();
//创建Thread类对象
Thread t = new Thread(run);
t.start();
//简化代码,使用匿名内部类,使用接口接收一下
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"创建新的线程");
}
};
new Thread(r).start();
//继续简化代码,使用匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"创建新的线程");
}
}).start();;
}
}
----------------------------------
public class LambdaTest01 {
public static void main(String[] args) {
//调用,参数是Cook接口
invokeCook(new Cook(){
public void makeFood(){
System.out.println("开饭");
}
});
//使用Lambda表达式,简化书写
invokeCook(()->{
System.out.println("开饭");
});
invokeCook(()->System.out.println("开饭"));
}
//定义一个方法,参数传递Cook接口,方法的内部调用Cook接口中方法makeFood
public static void invokeCook(Cook cook){
cook.makeFood();
}
}
--------------------------------
import java.util.Arrays;
import java.util.Comparator;
public class LambdaTestArray {
public static void main(String[] args) {
//创建数组,数组中的元素使用逗号隔开
Person[] arr = {
new Person("古力娜扎", 18),
new Person("迪丽热巴", 20),
new Person("小爱", 22)
};
//对数组中的进行升序排列
/* Arrays.sort(arr,new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
// TODO Auto-generated method stub
return o1.getAge()-o2.getAge();
}
});*/
//使用Lambda表达式,计划
Arrays.sort(arr,(Person o1,Person o2)->{
return o1.getAge()-o2.getAge();
});
//优化
Arrays.sort(arr,(Person o1,Person o2)->o1.getAge()-o2.getAge());
//遍历
for (Person person : arr) {
System.out.println(person);
}
}
}
-----------------------------
public class Person {
private String name;
private int age;
public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
----------------------------
public class RunnableImpl implements Runnable{
@Override
public void run() {
//获取线程名称
System.out.println(Thread.currentThread().getName()+"创建新的线程");
}
}
----------------------
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/*
* JDK1.5之后提供的
* 线程池-->容器 -->集合 (ArrayList,HashSet,LinkedList,HashMap)
* 当线程第一次启动的时候,创建多个线程,保存到集合当中,当我们要使用线程的时候
* 就可以从集合中取出来使用
* 当我们使用完毕需要江县城归还给线程池
*
* java.util.concurrent.Executors
* Executors类生产线程池的工厂类
* static ExecutorSerevice newFixedThreadPool(int nThread)
* 创建一个可重用固定线程数的线程池
* 参数:线程数量
* 返回值:ExecutorService接口,返回的是ExecutorService接口的实现类对象
* 我们使用ExecutorService接口接收(面向接口编程)
* java.util.concurrent.ExecutorService:线程池接口
* submit(Runable task) 提交一个Runable接口任务用于自行
* 关闭销毁线程池:
* shutdown();
*
* 线程池的使用:
* 使用工厂类里面的方法生产线程
* 创建一个类实现Runable接口,重写run方法,设置任务
* 调用ExecutorService中的方法submit,传递线程任务实现类,开启线程
* 调用shutdown方法销毁线程池,不建议执行
*
*
*
*/
public class XianChengPool {
public static void main(String[] args) {
//获取
ExecutorService es = Executors.newFixedThreadPool(2);
es.submit(new RunnableImpl());
es.submit(new RunnableImpl());
//有一个线程等着,等归还完之后继续使用,线程池会一直开启,使用完之后自动归还
es.submit(new RunnableImpl());
//销毁线程池
es.shutdown();
//没有线程池,不能在执行线程池后面的代码
// es.submit(new RunnableImpl());//抛异常
}
}