Java学习 day09

本文详细讲解了Java中的线程基础,包括如何创建线程、线程安全问题及其解决办法,如同步代码块和同步函数的使用。通过实例分析了线程通信、线程锁以及线程状态,最后探讨了线程的其它知识点,如匿名内部类、线程停止、守护线程和join()方法的使用。
摘要由CSDN通过智能技术生成

在这里插入图片描述

1 线程基础

2 线程创建

2.1 概述

2.2 直接使用Thread类创建线程对象

2.3 使用Thread子类创建线程对象


2.4 使用Runnable接口实现线程与任务分离


2.5 其它

(1)如果手动调用run,则失去了任务区的功能,变成了一个普通的方法,当run作为一个普通方法时,内部对应的线程和调用的位置保持一致

3 线程安全

3.1 产生线程安全问题的原因

(1)当多个线程共用一个数据时,则可能出现线程安全问题,因为当一个线程使用CPU还没有使用完时,CPU被抢走,当再次抢到CPU时,会直接执行后面的语句,造成错误的产生

3.2 如何解决线程安全问题

(1)在代码中使用同步代码块(同步锁),这样在某一段任务中,同一时间只允许一个线程执行任务,其它的线程即使抢到了CUP,也无法进入当前的任务区,只有当前的线程将任务执行完之后,其它的进程才可以进入

3.3 【样例】窗口售票问题


3.4 【比较】同步代码块和同步函数

(1)同步代码块使用更加灵活,只给需要同步的部分代码同步即可,而同步函数则是给这个函数内的所有代码同步,因此通常更建议使用同步代码块
(2)当一个类中存在多个synchronized修饰的代码块或函数时,出于安全性考虑,应当使得他们后面的对象一致,因为只有同一把锁才能安全
(3)同步函数的锁:this
(4)静态同步函数在进内存的时候不会创建对象,但是存在其所属类的字节码文件对象,属于class类型的对象,所以静态同步函数的锁是其所属类的字节码文件对象

3.5 synchronized关键字

(1)synchronized关键字的作用域有二种:
(1.1)是某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法;
(1.2)是某个类的范围,synchronized static aStaticMethod{}防止多个线程同时访问这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。

(2)除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。用法是: synchronized(this){/区块/},它的作用域是当前对象;

(3)synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法;

3.6 【样例】银行存钱问题


4 线程通信

4.1 【样例】打印机打印-一次输入一次输出





4.2 【样例】打印机打印-一次输入一次输出 - 优化




4.3 【代码】单生产者、单消费者问题
/* 生产者消费者:
* 单生产者单消费者-----会
* 多生产者多消费者-----了解
* 
* 先学习单生产者单消费者
* 需要的线程:两个---一个生产线程一个消费线程
* 需要的任务:两个---一个生产任务一个消费任务
* 需要数据:一份---产品
*/
public class Demo9 {
	public static void main(String[] args) {
		//准备数据
		Product product = new Product();
		//准备任务
		Producer producer = new Producer(product);
		Consumer consumer = new Consumer(product);
		//准备线程
		Thread proThread = new Thread(producer);
		Thread conThread = new Thread(consumer);
		//开启线程
		proThread.start();
		conThread.start();	
	}
}

//创建产品
class Product{
	String name;//产品的名字
	double price;//产品的价格
	int count;//生产的产品数量
	
	//标识
	boolean flag = false;
	
	//准备生产
	public synchronized void setProduce(String name,double price){
		if (flag == true) {
			try {
				wait();//让生产线程等待
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		this.name = name;
		this.price = price;
		System.out.println(Thread.currentThread().getName()+"   生产了:"+this.name+"   产品的数量:"+this.count+"   价格:"+this.price);
		
		count++;
		flag = ! flag;
		notify();//唤醒消费线程
	}
	//准备消费
	public  synchronized void getConsume() {
		if (flag == false) {
			try {
				wait();//让消费线程等待
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println(Thread.currentThread().getName()+"   消费了:"+this.name+"   产品的数量:"+this.count+"   价格:"+this.price);
		//唤醒生产线程
		flag = ! flag;
		notify();
	}
}
//创建生产任务
class Producer implements Runnable{
	Product product;
	public Producer(Product product) {
		super();
		this.product = product;
	}
	public void run() {
		while (true) {
			product.setProduce("bingbing", 10);
		}
		
	}
}
//创建消费任务
class Consumer implements Runnable{
	Product product;
	public Consumer(Product product) {
		super();
		this.product = product;
	}
	public void run() {
		while (true) {
			product.getConsume();
		}
	}
}

4.4 【代码】多生产者、多消费者问题
/* 生产者消费者:
* 
 * 学习多生产者多消费者
 * 需要的线程:四个---两个生产线程两个消费线程
 * 需要的任务:两个---一个生产任务一个消费任务
 * 需要数据:一份---产品
 * 
 * 生产任务与消费任务共用一个数据--产品类
 * 
 * 要求:最终也要实现一次生产一次消费
  *错误描述:当有两个生产线程,两个消费线程同时存在的时候,有可能出现生产一次,消费多次或者生产多次消费一次的情况.
 *原因:当线程被重新唤醒之后,没有判断标记,直接执行了下面的代码
 *
 *解决办法:将标记处的if改成while
 *
 *问题描述:继续运行程序,会出现死锁的情况(4个线程同时处于等待状态)
 *原因:唤醒的是本方的线程,最后导致所有的线程都处于等待状态.
 *
 *解决办法:将notify改成notifyAll.保证将对方的线程唤醒
 *
 *死锁:出现的情况有两种
 *1.所有的线程处于等待状态
 *2.锁之间进行嵌套调用
 *
 
*/
public class Demo10 {
	public static void main(String[] args) {
		//准备数据
		Product1 product = new Product1();
		//准备任务
		Producer1 producer = new Producer1(product);
		Consumer1 consumer = new Consumer1(product);
		//准备线程
		Thread proThread1 = new Thread(producer);
		Thread proThread2 = new Thread(producer);
		Thread conThread1 = new Thread(consumer);
		Thread conThread2 = new Thread(consumer);
		//开启线程
		proThread1.start();
		conThread1.start();	
		proThread2.start();
		conThread2.start();	
	}
}

//创建产品
class Product1{
	String name;//产品的名字
	double price;//产品的价格
	int count;//生产的产品数量
	
	//标识
	boolean flag = false;
	
	//准备生产
	public synchronized void setProduce(String name,double price){
		while (flag == true) {
			try {
				wait();//让生产线程等待
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		this.name = name;
		this.price = price;
		System.out.println(Thread.currentThread().getName()+"   生产了:"+this.name+"   产品的数量:"+this.count+"   价格:"+this.price);
		
		count++;
		flag = ! flag;
		//notify();//唤醒消费线程
		notifyAll();
	}
	//准备消费
	public  synchronized void getConsume() {
		while (flag == false) {
			try {
				wait();//让消费线程等待
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println(Thread.currentThread().getName()+"   消费了:"+this.name+"   产品的数量:"+this.count+"   价格:"+this.price);
		//唤醒生产线程
		flag = ! flag;
		//notify();
		notifyAll();
	}
}
//创建生产任务
class Producer1 implements Runnable{
	Product1 product;
	public Producer1(Product1 product) {
		super();
		this.product = product;
	}
	public void run() {
		while (true) {
			product.setProduce("bingbing", 10);
		}
		
	}
}
//创建消费任务
class Consumer1 implements Runnable{
	Product1 product;
	public Consumer1(Product1 product) {
		super();
		this.product = product;
	}
	public void run() {
		while (true) {
			product.getConsume();
		}
	}
}

5 线程锁

5.1 【比较】synchronized和Lock

5.2 【代码】多生产者、多消费者问题-Lock锁
public class Demo11 {
	public static void main(String[] args) {
		//准备数据
		Product2 product = new Product2();
		//准备任务
		Producer2 producer = new Producer2(product);
		Consumer2 consumer = new Consumer2(product);
		//准备线程
		Thread proThread1 = new Thread(producer);
		Thread proThread2 = new Thread(producer);
		Thread conThread1 = new Thread(consumer);
		Thread conThread2 = new Thread(consumer);
		//开启线程
		proThread1.start();
		conThread1.start();	
		proThread2.start();
		conThread2.start();	
	}
}

//创建产品
class Product2{
	String name;//产品的名字
	double price;//产品的价格
	int count;//生产的产品数量
	
	//标识
	boolean flag = false;
	
	//创建锁对象
	Lock lock = new ReentrantLock();
	//用于生产任务的Condition
	Condition proCon = lock.newCondition();
	//用于消费任务的Condition
	Condition conCon = lock.newCondition();
	
	//准备生产
	public  void setProduce(String name,double price){
		try {
			lock.lock();//获取锁
			while (flag == true) {
				try {
					//wait();//让生产线程等待
					proCon.await();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			
			this.name = name;
			this.price = price;
			System.out.println(Thread.currentThread().getName()+"   生产了:"+this.name+"   产品的数量:"+this.count+"   价格:"+this.price);
			
			count++;
			flag = ! flag;
			//notify();//唤醒消费线程
			//notifyAll();
			conCon.signal();
		}finally {
			lock.unlock();//释放锁
		}
		
	}
	//准备消费
	public   void getConsume() {
		try {
			lock.lock();
			while (flag == false) {
				try {
					//wait();//让消费线程等待
					conCon.await();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			System.out.println(Thread.currentThread().getName()+"   消费了:"+this.name+"   产品的数量:"+this.count+"   价格:"+this.price);
			//唤醒生产线程
			flag = ! flag;
			//notify();
			//notifyAll();
			proCon.signal();
		}finally {
			lock.unlock();
		}
	}
}
//创建生产任务
class Producer2 implements Runnable{
	Product2 product;
	public Producer2(Product2 product) {
		super();
		this.product = product;
	}
	public void run() {
		while (true) {
			product.setProduce("bingbing", 10);
		}
		
	}
}
//创建消费任务
class Consumer2 implements Runnable{
	Product2 product;
	public Consumer2(Product2 product) {
		super();
		this.product = product;
	}
	public void run() {
		while (true) {
			product.getConsume();
		}
	}
}

6 线程状态图

7 线程其它

7.1 匿名内部类、lambda表达式-开启线程

7.2 单例-线程

7.3 线程的停止



7.4 守护线程

7.5 join()方法

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值