Java基础——多线程2

Lock锁
  1. 概述:
    虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock,可以使用此对象,来表示锁的创建和释放
  2. 特点:
    (1)Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化
  3. 构造方法:
    ReentrantLock():创建一个ReentrantLock的实例
  4. 加锁解锁方法:
    void lock() :获得锁
    void unlock():释放锁
死锁
  1. 概述:
    线程死锁是指由两个或者多个线程互相持有并且需要对方的的资源,导致这些线程处于等待状态,无法前往执行
    线程A: 需要资源x,资源y 拥有资源x,需要资源y
    线程B: 需要资源x,资源y 拥有资源y,需要资源x

多线程中生产者和消费者模式

  1. 概述:
    生产者:提供数据或者资源的一方
    消费者:获取数据的一方
    2、案例:
    牛奶箱类型:
    成员变量 int :用来记录存放了几瓶奶
    成员方法:set:用来表示给存放牛奶;get:用来表示取出牛奶
    生产者类型:
    实现了Runnable接口,重写run方法,调用send方法,给牛奶箱存牛奶
    消费者:
    实现了Runnable接口,重写run方法,调用drink方法,获取牛奶
    测试类:
    创建牛奶箱对象,表示共享数据
    创建生产者对象,通过构造接收牛奶箱对象,因为需要使用set方法存牛奶
    创建消费者对象,通过构造方法接收牛奶箱对象,因为需要使用get方法取出牛奶
    创建两个线程,接收生产者和消费者对象
//牛奶箱
public class MilkBox {
	private int num;
	private boolean state = false;
	public synchronized void setMilk(int i) {
		if(state) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		num = i;
		System.out.println("已经送出第"+num+"瓶牛奶");
		state = true;
		notifyAll();
	}
	public synchronized void getMilk() {
		if(!state) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println("取出了第"+num+"瓶牛奶");
		state = false;
		notifyAll();
	}
}
//送牛奶的生产者
public class Producer implements Runnable{
	MilkBox box;
	public Producer(MilkBox box) {
		this.box= box;
	}
	@Override
	public void run() {
		for(int i = 1; i <= 5; i++) {
			box.setMilk(i);
		}
	}
}
//拿牛奶的消费者
public class Consumer implements Runnable{
	MilkBox box;
	public Consumer(MilkBox box) {
		this.box=box;
	}
	@Override
	public void run() {
		while(true) {
			box.getMilk();
		}
	}

}

//测试类
public static void main(String[] args) {
		MilkBox box = new MilkBox();
		Producer p = new Producer(box);
		Consumer c = new Consumer(box);
		Thread t1 = new Thread(p);
		Thread t2 = new Thread(c);
		t1.start();
		t2.start();
	}

线程的生命周期

  1. 概念:线程从创建到消亡的过程。在线程的生命周期中有很多的状态来描述。
  2. 线程的状态:
    新建态:在new一个线程对象之后
    就绪态:线程已经启动,start。资源已经准备完成,就差cpu来临
    运行态:cpu正在执行的状态
    阻塞态:线程休眠,IO数据,等待锁的一个状态
    死亡态:任务正常执行完成,发生异常停止,使用其他方法终止线程
Java语言中状态的描述
  1. 以上的状态都只是理论上线程的状态,也可以通过java代码回去线程中的状态描述。
  2. getState() :获取当前线程状态的方法
    返回值:Thread.State,表示Thread类的一个内部类,类中定义全都是对象,用来描述线程状态的对象。
  3. 状态:
    NEW:新建态
    RUNNABLE:运行态和就绪态
    BLOCKED:阻塞态 IO 等待锁
    WAITING:阻塞态 wait方法,让线程没有时间限制的休眠
    TIMED_WAITING:阻塞态 调用了sleep有时间限制的休眠
    TERMINATED:死亡态

线程池

  1. 概念:用来存储线程的一个容器。
  2. 原因:
    没有线程池:
    —如果需要完成一个任务,就需要创建一个线程对象,当任务完成之后,这个线程对象进行销毁,如果系统上有很多耗时比较短的任务,那么大量的时间全部浪费在线程的创建和销毁上,执行任务的效率就降低了。
    —如果某一个任务破坏力比较强,在线程执行任务的时候,线程被意外销毁,那么这个任务也就无法继续完成。
    有线程池:
    —线程池会默认提供一些创建好的线程,当有任务的时候会立即分配已经准备好的线程,当任务完成之后,线程会自动回收到线程池中,继续等待下一个任务。
    —当线程执行任务的时候,这条线程也有可能被任务破坏,如果这个线程被破坏,线程池会立即分配下一条线程继续执行这个任务,直到任务完成为止。
线程池的使用
  1. 步骤:
    1、先获取线程池对象
    2、创建任务类对象
    3、将任务对象提交给线程池
    4、关闭线程池对象
  2. 获取线程池对象:
    Executors:工具类 获取线程池的工具类
    -newSingleThreadExecutor() :获取一个具有单个线程的线程池对象
    -newFixedThreadPool(int n) :获取一个有n条线程的线程池对象
  3. 将任务提交给线程池对象:
    submit(Runnable r);
    注意事项:
    1、如果线程池中任务少,线程多。随机线程去执行任务,多余的线程继续等待任务
    2、如果线程池中任务和线程一样多,一个线程完成对应的一个任务
    3、如果线程池中任务多,线程少,每一个线程执行一个任务,多余的任务继续等待其他线程来执行。
  4. 关闭线程池的方法:
    shutdown() :将已经提交的任务全部完成,再关掉线程池
    shutdownNow() :将正在执行的任务全部完成,没有执行的已经提交的不完成。

单例设计模式

  1. 模式:生产实践中,积累的经验、办事情的套路
  2. 设计模式:在设计类型、设计接口、设计方法、完成某些架构的时候使用的套路,就是设计模式。
  3. 单例设计模式:
    在当前系统中,某个类型的对象,最多只能有一个,就需要使用单例设计模式
  4. 单例模式的设计原则:
    1、构造方法私有化
    2、在类中创建好该类对象
    3、在类中,给外界提供获取该对象的公有方式

枚举类型

  1. 用来描述有,有限个对象的类型
  2. 单例设计模式,设计出来的是某个类型的对象只有一个;
    枚举类型就是有指定个数对象的类型,也可以成为多例模式
  3. 声明一个枚举类型,使用的关键字是enum,声明出来的也是一个类,编译出来也是一个.class的文件。
自己实现枚举类型的第一种格式&使用枚举格式完成
  1. 自己实现:
    在一个类中,创建多个该类对象
  2. 使用枚举格式:
    1、使用enum关键字声明了一个枚举类型
    2、在枚举类型中,声明罗列了各个对象的名称
    3、在定义对象名称时,使用逗号将各个对象分隔,最后一个对象后面跟上分号
    4、在枚举类型中的各个对象,叫做【枚举项】
自己实现枚举类型的第二种格式&使用枚举格式完成
  1. 自己实现:
    类型中,有一个成员变量,在一个类中,创建多个该类对象
  2. 使用枚举格式:
    1、使用enum声明一个枚举类型
    2、在枚举类型中,声明一个成员变量
    3、私有化该类型的有参构造方法
    4、写出成员变量的get、set方法
    5、在枚举类型的第一行,写出枚举项(该类对象的名称),枚举项名称后面跟上小括号,小括号里面有有参构造的实际参数。
自己实现枚举类型的第三种格式&使用枚举格式完成
  1. 自己实现:
    在类型中,有成员变量、还有一个抽象方法
  2. 使用枚举格式:
    1、使用enum声明一个枚举类型
    2、在枚举类型中,声明一个成员变量
    3、提供该成员变量的私有的有参构造、get、set方法
    4、该枚举类型中,还定义了一个抽象方法
    5、在枚举类型的第一行,声明枚举项,枚举项名称后面需要跟上有参构造的实际参数,在实际参数后面跟上一个大括号,重写该枚举类型中的抽象方法(创建的是该枚举类型对象的子类对象)
枚举类型的注意事项
  1. 定义枚举类型必须使用enum关键字,创建的其实也是一个普通的类型。
  2. 所有的枚举项,必须定义在枚举类型的第一行,枚举项之间使用逗号分隔,最后一个枚举项之后需要使用分号结尾
  3. 枚举类型也有构造方法,只能默认提供空参构造,需要我们手动定义有参构造。在枚举类型中,所有的构造方法,都必须是私有化的。
  4. 枚举类型也可以有抽象方法,但是必须在枚举项中,将该方法实现。
枚举类型的常用方法
  1. 所有使用enum关键字声明的类型,全都是Enum类型的子类
  2. 常用特有方法:
    -compareTo(E e):用于比较两个枚举项的顺序,如果调用者序号小,则返回负数;如果调用者序号大,则返回正数;
    -ordinal():返回的就是枚举项的系数
    -name():返回该对象的对象名称(枚举项的名称),不能重写
    -toString():返回该对象的对象名称(枚举项的名称),可以重写
    -values():返回该枚举类型的所有枚举项
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值