线程创建方式,最后一种打赌你不知道
2021-02-26 21:34
369 查看
Java创建线程的几种方式
创建线程,是在多线程编程中最基本的操作,熟悉Java线程的应该很清楚有几种创建线程的方式。有关此类文章,也已经被网友们说烂了,八仙过海各显神通,甚至lambda表达式写法都被说了,但是说来说去,我发现只有一种没有被说,所以今天来挖掘一下新技能,也就是介绍这个“神秘”的办法,这种办法,多数人肯定不知道,因为不常用,但是也可以使实现,在此之前,我们先预习一下Java创建线程的方式。
继承Thread
这种方式有个缺点就是不能继承其他类了。
public class ThreadTest {
public static void main(String[] args) {
new MyThread().start();
}
static class MyThread extends Thread{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
}
实现Runnable接口
这种方式可以做到数据共享,即只创建一个Runnable,然后实例化多个Thread,并把Runnable传递进去。
package com.company;
public class ThreadTest {
public static void main(String[] args) {
MyThread myThread = new MyThread();
for (int i = 0; i < 10; i++) {
new Thread(myThread).start();
}
}
static class MyThread implements Runnable{
private int total;
private Object mutex =new Object();
@Override
public void run() {
synchronized (mutex){
for (int i = 0; i < 100; i++) {
total++;
}
}
System.out.println(Thread.currentThread().getName() +" "+total);
}
}
}
输出:
Thread-0 100
Thread-2 300
Thread-3 400
Thread-1 200
Thread-4 500
Thread-5 600
Thread-6 700
Thread-7 800
Thread-8 900
Thread-9 1000
FutureTask和Callable
使用这种办法,还可以阻塞到任务完成,并且还是有返回值的。
public class ThreadTest {
public static void main(String[] args) {
FutureTask<String> stringFutureTask = new FutureTask<>(new MyCallable());
new Thread(stringFutureTask).start();
}
static class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println(Thread.currentThread().getName());
return "OK";
}
}
}
Executors
还有就是使用线程池了,submit方法可以提交Callable,也可以提交Runnable。
public class ThreadTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(new MyCallable());
executorService.shutdown();
}
static class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println(Thread.currentThread().getName());
return "OK";
}
}
}
JNI
到了最后一种了,就是JNI调用,由C创建线程,线程中调用Runnable的run方法,也可以自定义一个对象,这种情况一般是用不到,但是在系统级别的地方可以用到,用来做回调处理,比如c中下载文件,回调进度的时候就需要在c中调用java对象的方法,另外JVM底层创建线程也是通过这种方式,即调用pthread_create函数。
一来一去,就实现了线程创建,下面在Linux平台下演示。
- 编写Java类startThread方法就是由c去实现,参数Runnable作为线程执行的地方。
package com.company;
public class JniThread {
public final native String startThread(Runnable runnable);
}
- 生成h文件。
javah -jni -classpath /home/HouXinLin/projects/java/Idea/Java-Project/ThreadDemo/out/production/ThreadDemo -d ./jni com.company.JniThread
- startThread实现。
#include "library.h"
#include "com_company_JniThread.h"
#include <pthread.h>
#include <stdio.h>
JavaVM *g_jvm = NULL;
jobject g_obj = NULL;
void *startThread(void *arg) {
int status;
JNIEnv *_jniEnv = NULL;
status = (*g_jvm)->GetEnv(g_jvm, (void **) &_jniEnv, JNI_VERSION_1_8);
if (status < 0) {
status = (*g_jvm)->AttachCurrentThread(g_jvm, (void **) &_jniEnv, NULL);
}
jclass runnableClass= (*_jniEnv)->FindClass(_jniEnv,"java/lang/Runnable");
jmethodID runId =(*_jniEnv)->GetMethodID(_jniEnv,runnableClass,"run","()V");
(*_jniEnv)->CallVoidMethod(_jniEnv,arg,runId);
(*g_jvm)->DetachCurrentThread(g_jvm);
return 0;
}
JNIEXPORT jstring JNICALL Java_com_company_JniThread_startThread
(JNIEnv *env, jobject job1, jobject job2) {
g_obj = (*env)->NewGlobalRef(env, job2);
pthread_t pthread;
pthread_create(&pthread, NULL, startThread, g_obj);
return (*env)->NewStringUTF(env, "OK");
}
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
g_jvm = vm;
return JNI_VERSION_1_8;
}
- 测试
package com.company;
public class Main {
public static void main(String[] args) throws InterruptedException {
String strLibPath = "/home/HouXinLin/projects/c/JniThread/libtest.so";
System.load(strLibPath);
JniThread jniThread = new JniThread();
jniThread.startThread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
Thread.sleep(2000);
}
}
所以有什么用呢?
答:面试装x
相关文章推荐
- 你选择哪一种方式创建线程?
- 创建线程有几种不同的方式?哪一种比较受欢迎?为什么?
- 线程:创建线程有两种方式,一种是继承Thread类,另一种是实现Runnable接口。代码如下:
- 创建线程有几种不同的方式?你喜欢哪一种?为什么?
- IPhone中创建线程的令一种简单方式
- csdn java创建线程的三种方式及其对比
- java线程两种创建方式的区别与模拟买票情景
- linux 线程创建函数pthread_create的几个传参方式
- 多线程:创建线程的几种方式
- 创建线程的三种方式及对比
- [Java并发编程]-创建线程的两种方式及区别
- 线程创建的几种方式
- Java创建线程的一种方法
- 创建线程的两种方式
- boost::thread线程创建方式总结
- 线程创建方式以及主要方法简介 简单易懂
- Java中创建线程的主要三种方式
- Java创建线程的两种方式
- 创建线程的三种方式对比(总结)
- python中threading方式创建的线程的终止