理解多线程,使用synchronized简单实现多生产者多消费者
区分程序,进程和线程的概念:
- 程序:一个可执行的文件
- 进程:一个正在运行的程序.也可以理解成在内存中开辟了一块儿空间
- 线程:负责程序的运行,可以看做一条执行的通道或执行单元,所以我们通常将进程的工作理解成线程的工作
打个比方,程序是一家没有业务的公司,进程就是这家公司接到业务了,线程是指负责这个业务的具体实施人.
所以一个进程至少有一个线程,就像一个公司怎么着都得有一个老板.
多线程的作用:实现同一个时间干多件事情.
如果你知道操作系统的一点知识的话,你就明白事实上cpu同一个时间只能执行一个线程.
而众所周知:人的眼睛一秒钟观察到24帧以上的画面就会认为是连续的.
人类的时间单位是秒,cpu的时间单位可就小多了.
进程有三种状态
分配到时间片之后,就绪态进程就可以转为运行态,时间片耗尽后,cpu分发下个时间片,所有就绪态的进程都会去抢夺时间片,抢到后进入下一个的轮回.
所以多线程会无序的执行多个任务.
为了解决在并发编程中存在的线程安全问题,我们要使用锁。关键字synchronized可以保证在同一时刻,只有一个线程可以执行某个方法或某个代码块
理解synchronized关键字
1、synchronized关键字的作用域有二种:
- 1)是某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象
的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的
一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。
这时,不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时
访问相同类的另一个对象实例中的synchronized方法; - 2)是某个类的范围,synchronized static aStaticMethod{}防止多个线程同时访问
这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。
2、除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,
表示只对这个区块的资源实行互斥访问。用法是: synchronized(this){/区块/},它的作用域是当前对象;
3、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){}
在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定
它的某个方法为synchronized方法.
使用synchronized简单实现多生产者多消费者
//synchronized多生产者多消费者
public class ThreadTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
//准备产品
Product product = new Product("哪吒手办",100);
//创建生产者和消费者任务
Producer producer = new Producer(product);
Consumer consumer = new Consumer(product);
//创建多线程
Thread prot0 = new Thread(producer);
Thread prot1 = new Thread(producer);
Thread cont2 = new Thread(consumer);
Thread cont3 = new Thread(consumer);
//开启多线程
prot0.start();
prot1.start();
cont2.start();
cont3.start();
}
}
class Product{
private String name;//产品名称
private int num;//产品数量
boolean flag;//标识
public Product() {
super();
// TODO Auto-gsenerated constructor stub
}
public Product(String name, int num) {
super();
this.name = name;
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
//生产功能
public synchronized void produce() {
while(flag == true) {//单生产者单消费者while换成if即可
try {
wait();//生产线程进入等待
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"生产:" + name + ",库存数量:" + (num++));
flag = !flag;
//notify();
notifyAll();//唤醒消费线程
}
//消费功能
public synchronized void consume() {
while(flag == false) {//单生产者单消费者while换成if即可
try {
wait();//消费线程进入等待
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"消费:"+name+",库存数量:"+(num--));
flag = !flag;
//notify();
notifyAll();//唤醒生产线程
}
}
class Producer implements Runnable{
Product product;
public Producer(Product product) {
super();
this.product = product;
}
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0; i < 100; i++) {
product.produce();
}
}
}
class Consumer implements Runnable{
Product product;
public Consumer(Product product) {
super();
this.product = product;
}
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0; i < 100; i++) {
product.consume();
}
}
}