我的视频课程(基础):《(NDK)FFmpeg打造Android万能音频播放器》
我的视频课程(进阶):《(NDK)FFmpeg打造Android视频播放器》
我的视频课程(编码直播推流):《Android视频编码和直播推流》
我的视频课程(C++ OpenGL):《Android C++ OpenGL教程》
目录:
Android-Jni线程(三)— JNI全局回调java方法
上一篇博客《Android-Jni线程(一)— 创建线程》我们在Jni层创建了一个最简单的线程但啥事也没有做,总感觉没什么实际的作用,现在我们就来实现经典的“生产者和消费者”线程锁模型。先看看演示效果:
首先还是老规矩先讲讲大体步骤:
1、创建生产者和消费者2个线程:pthread_t pthread_produc,pthread_customer。
2、创建线程锁和条件对象:pthread_mutex_t mutex和pthread_cond_t cond。
3、创建产品队列queue(C++中“queue”头文件)。
5、生产者定时生产产品往队列queue添加(push)产品,并通知(pthread_cond_signal)消费者可以消费了;消费者快速从queue取出(pop)产品消费,当queue中没有产品(size == 0)时,就阻塞等待(pthread_cond_wait)生产者生产产品后的通知并马上消费。
6、生产者添加产品(queue.push)和消费者消费产品(queue.pop)时都在线程锁中(pthread_mutex_lock)执行,当添加/消费产品后就解锁线程(pthread_mutex_unlock),这样就能保证同一时刻只有生产者或消费者才能对产品进行操作。
接下来Jni中用C++代码实现:
#include <jni.h>
#include "AndroidLog.h"
#include "pthread.h"
#include "unistd.h"
#include "queue"
//1、一般线程
pthread_t pthread;//线程对象
void *threadDoThings(void *data)
{
LOGD("jni thread do things");
pthread_exit(&pthread);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_ywl5320_jnithread_JniThread_normalThread(JNIEnv *env, jobject instance) {
// TODO
LOGD("normal thread");
//创建线程
pthread_create(&pthread, NULL, threadDoThings, NULL);
}
//2、线程锁
std::queue<int> queue; //产品队列,里面是int的队列
pthread_t pthread_produc; //生产者线程
pthread_t pthread_customer; //消费者线程
pthread_mutex_t mutex; //线程锁
pthread_cond_t cond; //条件对象
void *ptoducThread(void *data)
{
while(queue.size() < 50)
{
LOGD("生产者生产一个产品");
pthread_mutex_lock(&mutex); //操作队列前先加锁
queue.push(1);
if(queue.size() > 0)
{
LOGD("生产者通知消费者有产品产生,产品数量为:%d", queue.size());
pthread_cond_signal(&cond); //有了产品通知消费者
}
pthread_mutex_unlock(&mutex); //解锁线程
sleep(4); //休息4秒,单位是秒
}
pthread_exit(&pthread_produc);
}
void *customerThread(void *data)
{
char *prod = (char *) data;
LOGD("%", prod);
while(1) //这里用死循环,时间情况应该给一个变量来控制跳出循环
{
pthread_mutex_lock(&mutex); //操作队列前先加锁
if(queue.size() > 0)
{
queue.pop();
LOGE("消费者消费一个产品,产品数量为:%d", queue.size());
} else{
LOGE("产品消费完了,等待生产者生产......");
pthread_cond_wait(&cond, &mutex); //阻塞线程等待生产者的通知
}
pthread_mutex_unlock(&mutex);//解锁线程
usleep(500 * 1000); //休息0.5秒,usleep单位是微妙
}
pthread_exit(&pthread_customer);
}
void initMutex()
{
pthread_mutex_init(&mutex, NULL); //初始化锁对象 对应pthread_mutex_destroy销毁锁对象
pthread_cond_init(&cond, NULL); //初始化条件变量 对应pthread_cond_destroy销毁条件变量
pthread_create(&pthread_produc, NULL, ptoducThread, (void *) "product"); //创建生产者线程,并传递参数
pthread_create(&pthread_customer, NULL, customerThread, NULL); //创建消费者线程
}
extern "C"
JNIEXPORT void JNICALL
Java_com_ywl5320_jnithread_JniThread_mutexThread(JNIEnv *env, jobject instance) {
// TODO
//初始化时,先往队列中添加10个产品
for(int i = 0; i < 10; i++)
{
queue.push(i);
}
initMutex();
}
根据注释和上文的步骤思路就很好理解“生产者和消费者”模型了,在ffmpeg中音视频解码时就用到了这个模型,后面也会介绍用ffmpeg解码音视频的。现在是打基础的时候 哈哈。下一篇博客将介绍:在c++中全局调用java方法达到回调效果。
源码下载:Github:Android-JniThread 欢迎star