Java线程生产者消费者模式与线程池

首先先简单地介绍一下生产者消费者模式:

例如学到的知识

Teacher(上课讲知识,造知识)=========(知识)>>Student(学生学习知识,用知识)

这就是简单的生产者消费者模式

下面来介绍一个示例来学习此概念

有一个类似Hibernate的SessionFactory工厂

MakeSessionFactory为造工厂,GetSessionFactory为使用工厂,则SessionFactory为中间类

现在实现初步的生产者消费者:version 1 code:

thread_1.SessionFactory
thread_1.GetSessionFactory
thread_1.SetSessionFactory
thread_1.SessionFactoryTest

有如下问题:

A:在每个线程中都创建了资源,每次的输出结果是null-0

已解决:在生产者消费者类中提供一个带SessionFactory的构造函数,每次传递的时候都能保持使用SessionFactory同一个对象

B:为了数据能够出现效果,加入了大条件循环,但是给出了不同的值:

同一个数据出现多次:因为cpu

配置文件名和工厂名不匹配:那是因为如果if语句刚执行好没结束就没else抢去了执行权,所以在输出时的信息不准确,例如:

in get... sessionFactory is[SessionFactory{factoryName='spring-log4j.appender.stdout.layout.ConversionPattern', configName='applicationContext.xml'}]==========

而且执行时顺序也发生了问题,如下

10:15:01,828  INFO Spring4Hibernate5BaseUtils:182 - in make i = [-2146097274]==========
10:15:01,828  INFO Spring4Hibernate5BaseUtils:182 - in make i = [-2146097273]==========
10:15:01,828  INFO Spring4Hibernate5BaseUtils:182 - in make i = [-2146097272]==========
10:15:01,828  INFO Spring4Hibernate5BaseUtils:182 - in make i = [-2146097271]==========
10:15:01,828  INFO Spring4Hibernate5BaseUtils:182 - in make i = [-2146097270]==========
10:15:01,828  INFO Spring4Hibernate5BaseUtils:182 - in make i = [-2146097269]==========
10:15:01,828  INFO Spring4Hibernate5BaseUtils:182 - in make i = [-2146097268]==========
10:15:01,828  INFO Spring4Hibernate5BaseUtils:182 - in make i = [-2146097267]==========
10:15:01,827  INFO Spring4Hibernate5BaseUtils:182 - in get... sessionFactory is[SessionFactory{factoryName='interface org.hibernate.SessionFactory', configName='hibernate.cfg.xml'}]==========

关于输出内容写到了日志,可以复制log4j.properties文件来实现,可以到日志中去查看可以发现有以上这种情况

C:现在来解决以上问题:解决方案是加锁,加锁需注意:

1.不同种类的线程都要加锁

2.不同种类的线程加的锁必须是同一把

如果不是同一把锁会发生空的情况,这也会作为一个例子

D:加好同一把锁后发现输出一大片不太好看,可以通过java等待唤醒机制来实现

Object类中提供了三个方法:

wait():等待

notify():唤醒单个线程

notifyAll():唤醒全部线程

这些方法定义在Object类中的原因是通过锁对象调用,而获取的锁可以是任意对象,所以这些方法必须定义在Object类中才能被任意类型的子类调用

finalVersion:把设置和获取的操作封装成了功能,并增加了同步,

设置只需要调用实体类方法即可

线程池:

好处:

线程池里的每一个线程结束后并不会死亡,而是回到线程池中成为空闲状态,等待下一个对象来调用

A:创建一个线程池对象,控制要创建几个线程对象。

public static ExecutorService newFixedThreadPool(int nThreads)

B:这种线程池的线程可以执行:

可以执行Runnable对象或者Callable对象代表的线程

做一个类实现Runnable接口。

C:调用如下方法即可

Future> submit(Runnable task)
 Future submit(Callable task)

D:我就要结束,可以吗?

可以。

Callable:带返回值的Runnable式接口,接下来做一个示例来描述我的Callable