精华内容
下载资源
问答
  • 在 Windows 中实现 Java 本地方法David Wendt1999 年 5 月 01 日发布简介本文提供调用本地 C 代码的 Java代码示例,包括传递和返回某些常用的数据类型。本地方法包含在特定于平台的可执行文件中。就本文中的示例而言...

    在 Windows 中实现 Java 本地方法

    2771ca892c7b2591131a36eb05b9a9bb.png

    David Wendt

    1999 年 5 月 01 日发布

    简介

    本文提供调用本地 C 代码的 Java

    代码示例,包括传递和返回某些常用的数据类型。本地方法包含在特定于平台的可执行文件中。就本文中的示例而言,本地方法包含在

    Windows 32 位动态链接库 (DLL) 中。

    不过我要提醒您,对 Java 外部的调用通常不能移植到其他平台上,在

    applet 中还可能引发安全异常。实现本地代码将使您的 Java

    应用程序无法通过 100% 纯 Java

    测试。但是,如果必须执行本地调用,则要考虑几个准则:将您的所有本地方法都封装在单个类中,这个类调用单个

    DLL。对于每种目标操作系统,都可以用特定于适当平台的版本替换这个

    DLL。这样就可以将本地代码的影响减至最小,并有助于将以后所需的移植问题包含在内。

    本地方法要简单。尽量将您的 DLL 对任何第三方(包括

    Microsoft)运行时 DLL

    的依赖减到最小。使您的本地方法尽量独立,以将加载您的 DLL

    和应用程序所需的开销减到最小。如果需要运行时

    DLL,必须随应用程序一起提供它们。

    Java 调用 C

    对于调用 C 函数的 Java 方法,必须在 Java

    类中声明一个本地方法。在本部分的所有示例中,我们将创建一个名为

    MyNative

    的类,并逐步在其中加入新的功能。这强调了一种思想,即将本地方法集中在单个类中,以便将以后所需的移植工作减到最少。

    示例 1 -- 传递参数

    在第一个示例中,我们将三个常用参数类型传递给本地函数:

    String、

    int和

    boolean 。本例说明在本地 C

    代码中如何引用这些参数。public class MyNative

    {

    public void showParms( String s, int i, boolean b )

    {

    showParms0( s, i , b );

    }

    private native void showParms0( String s, int i, boolean b );

    static

    {

    System.loadLibrary( "MyNative" );

    }

    }

    请注意,本地方法被声明为专用的,并创建了一个包装方法用于公用目的。这进一步将本地方法同代码的其余部分隔离开来,从而允许针对所需的平台对它进行优化。

    static子句加载包含本地方法实现的 DLL。

    下一步是生成 C 代码来实现 showParms0 方法。此方法的 C

    函数原型是通过对 .class 文件使用 javah 实用程序来创建的,而 .class

    文件是通过编译 MyNative.java 文件生成的。这个实用程序可在 JDK

    中找到。下面是 javah 的用法:javac MyNative.java(将 .java 编译为 .class)

    javah -jni

    MyNative(生成 .h 文件)

    这将生成一个 MyNative.h 文件,其中包含一个本地方法原型,如下所示:/*

    * Class: MyNative

    * Method: showParms0

    * Signature: (Ljava/lang/String;IZ)V

    */

    JNIEXPORT void JNICALL Java_MyNative_showParms0

    (JNIEnv *, jobject, jstring, jint, jboolean);

    第一个参数是调用 JNI 方法时使用的 JNI Environment 指针。第二个参数是指向在此 Java 代码中实例化的 Java 对象 MyNative 的一个句柄。其他参数是方法本身的参数。请注意,MyNative.h 包括头文件 jni.h。jni.h 包含 JNI API 和变量类型(包括jobject、jstring、jint、jboolean,等等)的原型和其他声明。

    本地方法是在文件 MyNative.c 中用 C 语言实现的:#include

    #include "MyNative.h"

    JNIEXPORT void JNICALL Java_MyNative_showParms0

    (JNIEnv *env, jobject obj, jstring s, jint i, jboolean b)

    {

    const char* szStr = (*env)->GetStringUTFChars( env, s, 0 );

    printf( "String = [%s]\n", szStr );

    printf( "int = %d\n", i );

    printf( "boolean = %s\n", (b==JNI_TRUE ? "true" : "false") );

    (*env)->ReleaseStringUTFChars( env, s, szStr );

    }

    JNI API,GetStringUTFChars,用来根据 Java 字符串或 jstring 参数创建 C 字符串。这是必需的,因为在本地代码中不能直接读取 Java 字符串,而必须将其转换为 C 字符串或 Unicode。有关转换 Java 字符串的详细信息,请参阅标题为 NLS Strings and JNI 的一篇论文。但是,jboolean 和 jint 值可以直接使用。

    MyNative.dll 是通过编译 C 源文件创建的。下面的编译语句使用 Microsoft Visual C++ 编译器:cl -Ic:\jdk1.1.6\include -Ic:\jdk1.1.6\include\win32 -LD MyNative.c

    -FeMyNative.dll

    其中 c:\jdk1.1.6 是 JDK 的安装路径。

    MyNative.dll 已创建好,现在就可将其用于 MyNative 类了。

    可以这样测试这个本地方法:在 MyNative 类中创建一个 main 方法来调用 showParms 方法,如下所示:public static void main( String[] args )

    {

    MyNative obj = new MyNative();

    obj.showParms( "Hello", 23, true );

    obj.showParms( "World", 34, false );

    }

    当运行这个 Java 应用程序时,请确保 MyNative.dll 位于 Windows 的 PATH 环境变量所指定的路径中或当前目录下。当执行此 Java 程序时,如果未找到这个 DLL,您可能会看到以下的消息:java MyNative

    Can't find class MyNative

    这是因为 static 子句无法加载这个 DLL,所以在初始化 MyNative 类时引发异常。Java 解释器处理这个异常,并报告一个一般错误,指出找不到这个类。

    如果用 -verbose 命令行选项运行解释器,您将看到它因找不到这个 DLL 而加载 UnsatisfiedLinkError 异常。

    如果此 Java 程序完成运行,就会输出以下内容:java MyNative

    String = [Hello]

    int = 23

    boolean = true

    String = [World]

    int

    = 34

    boolean = false示例 2 -- 返回一个值

    本例将说明如何在本地方法中实现返回代码。

    将这个方法添加到 MyNative 类中,这个类现在变为以下形式:public class MyNative

    {

    public void showParms( String s, int i, boolean b )

    {

    showParms0( s, i , b );

    }

    public int hypotenuse( int a, int b )

    {

    return hyptenuse0( a, b );

    }

    private native void showParms0( String s, int i, boolean b );

    private native int hypotenuse0( int a, int b );

    static

    {

    System.loadLibrary( "MyNative" );

    }

    /* 测试本地方法 */

    public static void main( String[] args )

    {

    MyNative obj = new MyNative();

    System.out.println( obj.hypotenuse(3,4) );

    System.out.println( obj.hypotenuse(9,12) );

    }

    }

    公用的 hypotenuse 方法调用本地方法 hypotenuse0 来根据传递的参数计算值,并将结果作为一个整数返回。这个新本地方法的原型是使用 javah 生成的。请注意,每次运行这个实用程序时,它将自动覆盖当前目录中的 MyNative.h。按以下方式执行 javah:javah -jni MyNative

    生成的 MyNative.h 现在包含 hypotenuse0 原型,如下所示:/*

    * Class: MyNative

    * Method: hypotenuse0

    * Signature: (II)I

    */

    JNIEXPORT jint JNICALL Java_MyNative_hypotenuse0

    (JNIEnv *, jobject, jint, jint);

    该方法是在 MyNative.c 源文件中实现的,如下所示:#include

    #include

    #include "MyNative.h"

    JNIEXPORT void JNICALL Java_MyNative_showParms0

    (JNIEnv *env, jobject obj, jstring s, jint i, jboolean b)

    {

    const char* szStr = (*env)->GetStringUTFChars( env, s, 0 );

    printf( "String = [%s]\n", szStr );

    printf( "int = %d\n", i );

    printf( "boolean = %s\n", (b==JNI_TRUE ? "true" : "false") );

    (*env)->ReleaseStringUTFChars( env, s, szStr );

    }

    JNIEXPORT jint JNICALL Java_MyNative_hypotenuse0

    (JNIEnv *env, jobject obj, jint a, jint b)

    {

    int rtn = (int)sqrt( (double)( (a*a) + (b*b) ) );

    return (jint)rtn;

    }

    再次请注意,jint 和 int 值是可互换的。

    使用相同的编译语句重新编译这个 DLL:cl -Ic:\jdk1.1.6\include -Ic:\jdk1.1.6\include\win32 -LD MyNative.c

    -FeMyNative.dll

    现在执行 java MyNative 将输出 5 和 15 作为斜边的值。示例 3 -- 静态方法

    您可能在上面的示例中已经注意到,实例化的 MyNative 对象是没必要的。实用方法通常不需要实际的对象,通常都将它们创建为静态方法。本例说明如何用一个静态方法实现上面的示例。更改 MyNative.java 中的方法签名,以使它们成为静态方法:public static int hypotenuse( int a, int b )

    {

    return hypotenuse0(a,b);

    }

    ...

    private static native int hypotenuse0( int a, int b );

    现在运行 javah 为

    hypotenuse0创建一个新原型,生成的原型如下所示:/*

    * Class: MyNative

    * Method: hypotenuse0

    * Signature: (II)I

    */

    JNIEXPORT jint JNICALL Java_MyNative_hypotenuse0

    (JNIEnv *, jclass, jint, jint);

    C 源代码中的方法签名变了,但代码还保持原样:JNIEXPORT jint JNICALL Java_MyNative_hypotenuse0

    (JNIEnv *env, jclass cls, jint a, jint b)

    {

    int rtn = (int)sqrt( (double)( (a*a) + (b*b) ) );

    return (jint)rtn;

    }

    本质上,jobject 参数已变为 jclass 参数。此参数是指向 MyNative.class 的一个句柄。main 方法可更改为以下形式:public static void main( String[] args )

    {

    System.out.println( MyNative.hypotenuse( 3, 4 ) );

    System.out.println( MyNative.hypotenuse( 9, 12 ) );

    }

    因为方法是静态的,所以调用它不需要实例化 MyNative 对象。本文后面的示例将使用静态方法。示例 4 -- 传递数组

    本例说明如何传递数组型参数。本例使用一个基本类型,boolean,并将更改数组元素。下一个示例将访问 String(非基本类型)数组。将下面的方法添加到 MyNative.java 源代码中:public static void setArray( boolean[] ba )

    {

    for( int i=0; i < ba.length; i++ )

    ba[i] = true;

    setArray0( ba );

    }

    ...

    private static native void setArray0( boolean[] ba );

    在本例中,布尔型数组被初始化为 true,本地方法将把特定的元素设置为 false。同时,在 Java 源代码中,我们可以更改 main 以使其包含测试代码:boolean[] ba = new boolean[5];

    MyNative.setArray( ba );

    for( int i=0; i < ba.length; i++ )

    System.out.println( ba[i] );

    在编译源代码并执行 javah 以后,MyNative.h 头文件包含以下的原型:/*

    * Class: MyNative

    * Method: setArray0

    * Signature: ([Z)V

    */

    JNIEXPORT void JNICALL Java_MyNative_setArray0

    (JNIEnv *, jclass, jbooleanArray);

    请注意,布尔型数组是作为单个名为 jbooleanArray 的类型创建的。

    基本类型有它们自已的数组类型,如 jintArray 和 jcharArray。

    非基本类型的数组使用 jobjectArray 类型。下一个示例中包括一个 jobjectArray。这个布尔数组的数组元素是通过 JNI 方法 GetBooleanArrayElements 来访问的。

    针对每种基本类型都有等价的方法。这个本地方法是如下实现的:JNIEXPORT void JNICALL Java_MyNative_setArray0

    (JNIEnv *env, jclass cls, jbooleanArray ba)

    {

    jboolean* pba = (*env)->GetBooleanArrayElements( env, ba, 0 );

    jsize len = (*env)->GetArrayLength(env, ba);

    int i=0;

    // 更改偶数数组元素

    for( i=0; i < len; i+=2 )

    pba[i] = JNI_FALSE;

    (*env)->ReleaseBooleanArrayElements( env, ba, pba, 0 );

    }

    指向布尔型数组的指针可以使用 GetBooleanArrayElements 获得。

    数组大小可以用 GetArrayLength 方法获得。使用 ReleaseBooleanArrayElements 方法释放数组。现在就可以读取和修改数组元素的值了。jsize 声明等价于 jint(要查看它的定义,请参阅 JDK 的 include 目录下的 jni.h 头文件)。示例 5 -- 传递 Java String 数组

    本例将通过最常用的非基本类型,Java String,说明如何访问非基本对象的数组。字符串数组被传递给本地方法,而本地方法只是将它们显示到控制台上。

    MyNative 类定义中添加了以下几个方法:public static void showStrings( String[] sa )

    {

    showStrings0( sa );

    }

    private static void showStrings0( String[] sa );

    并在

    main 方法中添加了两行进行测试:String[] sa = new String[] { "Hello,", "world!", "JNI", "is", "fun." };

    MyNative.showStrings( sa );

    本地方法分别访问每个元素,其实现如下所示。JNIEXPORT void JNICALL Java_MyNative_showStrings0

    (JNIEnv *env, jclass cls, jobjectArray sa)

    {

    int len = (*env)->GetArrayLength( env, sa );

    int i=0;

    for( i=0; i < len; i++ )

    {

    jobject obj = (*env)->GetObjectArrayElement(env, sa, i);

    jstring str = (jstring)obj;

    const char* szStr = (*env)->GetStringUTFChars( env, str, 0 );

    printf( "%s ", szStr );

    (*env)->ReleaseStringUTFChars( env, str, szStr );

    }

    printf( "\n" );

    }

    数组元素可以通过 GetObjectArrayElement 访问。

    在本例中,我们知道返回值是 jstring 类型,所以可以安全地将它从 jobject 类型转换为 jstring 类型。字符串是通过前面讨论过的方法打印的。有关在 Windows 中处理 Java 字符串的信息,请参阅标题为 NLS Strings and JNI 的一篇论文。示例 6 -- 返回 Java String 数组

    最后一个示例说明如何在本地代码中创建一个字符串数组并将它返回给 Java 调用者。MyNative.java 中添加了以下几个方法:public static String[] getStrings()

    {

    return getStrings0();

    }

    private static native String[] getStrings0();

    更改

    main 以使

    showStrings 将

    getStrings 的输出显示出来:MyNative.showStrings( MyNative.getStrings() );

    实现的本地方法返回五个字符串。JNIEXPORT jobjectArray JNICALL Java_MyNative_getStrings0

    (JNIEnv *env, jclass cls)

    {

    jstring str;

    jobjectArray args = 0;

    jsize len = 5;

    char* sa[] = { "Hello,", "world!", "JNI", "is", "fun" };

    int i=0;

    args = (*env)->NewObjectArray(env, len, (*env)->FindClass(env, "java/lang/String"), 0);

    for( i=0; i < len; i++ )

    {

    str = (*env)->NewStringUTF( env, sa[i] );

    (*env)->SetObjectArrayElement(env, args, i, str);

    }

    return args;

    }

    字符串数组是通过调用 NewObjectArray 创建的,同时传递了 String 类和数组长度两个参数。Java String 是使用 NewStringUTF 创建的。String 元素是使用 SetObjectArrayElement 存入数组中的。

    调试

    现在您已经为您的应用程序创建了一个本地 DLL,但在调试时还要牢记以下几点。如果使用 Java 调试器 java_g.exe,则还需要创建 DLL 的一个“调试”版本。这只是表示必须创建同名但带有一个 _g 后缀的 DLL 版本。就 MyNative.dll 而言,使用 java_g.exe 要求在 Windows 的 PATH 环境指定的路径中有一个 MyNative_g.dll 文件。在大多数情况下,这个 DLL 可以通过将原文件重命名或复制为其名称带缀 _g 的文件。

    现在,Java 调试器不允许您进入本地代码,但您可以在 Java 环境外使用 C 调试器(如 Microsoft Visual C++)调试本地方法。首先将源文件导入一个项目中。

    将编译设置调整为在编译时将 include 目录包括在内:c:\jdk1.1.6\include;c:\jdk1.1.6\include\win32

    将配置设置为以调试模式编译 DLL。在 Project Settings 中的 Debug 下,将可执行文件设置为 java.exe(或者 java_g.exe,但要确保您生成了一个 _g.dll 文件)。程序参数包括包含 main 的类名。如果在 DLL 中设置了断点,则当调用本地方法时,执行将在适当的地方停止。

    下面是设置一个 Visual C++ 6.0 项目来调试本地方法的步骤。在 Visual C++ 中创建一个 Win32 DLL 项目,并将 .c 和 .h

    文件添加到这个项目中。

    82af17a2015f337293aa67e2c2dc4140.png

    82af17a2015f337293aa67e2c2dc4140.png

    9d6f4a395394fa49b2b77e3be42cc7fb.png

    9d6f4a395394fa49b2b77e3be42cc7fb.png在 Tools 下拉式菜单的 Options 设置下设置 JDK 的 include

    目录。下面的对话框显示了这些目录。

    afb5d375f7e9682d5bfb94b4692f994c.png

    afb5d375f7e9682d5bfb94b4692f994c.png选择 Build 下拉式菜单下的 Build MyNative.dll

    来建立这个项目。确保将项目的活动配置设置为调试(这通常是缺省值)。

    在 Project Settings 下,设置 Debug 选项卡来调用适当的 Java

    解释器,如下所示:

    9b871ab7bc7474c34a8841706059fc35.png

    9b871ab7bc7474c34a8841706059fc35.png

    当执行这个程序时,忽略“在 java.exe 中找不到任何调试信息”的消息。当调用本地方法时,在 C 代码中设置的任何断点将在适当的地方停止 Java 程序的执行。

    其他信息JNI 方法和 C++

    上面这些示例说明了如何在 C 源文件中使用 JNI 方法。如果使用 C++,则请将相应方法的格式从:(*env)->JNIMethod( env, .... );

    更改为:env->JNIMethod( ... );

    在 C++ 中,JNI 函数被看作是 JNIEnv 类的成员方法。字符串和国家语言支持

    本文中使用的技术用 UTF 方法来转换字符串。使用这些方法只是为了方便起见,如果应用程序需要国家语言支持 (NLS),则不能使用这些方法。有关在 Windows 和 NLS 环境中处理 Java 字符串正确方法,请参标题为 NLS Strings and JNI 的一篇论文。

    小结

    本文提供的示例用最常用的数据类据(如 jint 和 jstring)说明了如何实现本地方法,并讨论了 Windows 特定的几个问题,如显示字符串。本文提供的示例并未包括全部 JNI,JNI 还包括其他参数类型,如 jfloat、jdouble、jshort、jbyte 和 jfieldID,以及用来处理这些类型的方法。有关这个主题的详细信息,请参阅 Sun Microsystems 提供的 Java 本地接口规范。

    展开全文
  • 一.currentThread()方法...该方法为一个本地方法,原码如下:/*** Returns a reference to the currently executing thread object.**@returnthe currently executing thread.*/public static native Thread c...

    一.currentThread()方法

    currentThread方法就是返回当前被调用的线程。

    该方法为一个本地方法,原码如下:

    /*** Returns a reference to the currently executing thread object.

    *

    *@returnthe currently executing thread.*/

    public static native Thread currentThread();

    可以看出他返回的是一个线程对象。

    下面来看一个列子:

    public class CurrentThreadText extendsThread{publicCurrentThreadText(){

    System.out.println("构造器被"+Thread.currentThread().getName()+"线程调用了");

    }

    @Overridepublic voidrun(){

    System.out.println("run方法被"+Thread.currentThread().getName()+"线程调用了");

    }public static voidmain(String[] args) {

    System.out.println("main方法被"+Thread.currentThread().getName()+"线程调用了");

    CurrentThreadText cu=newCurrentThreadText();

    cu.start();

    }

    }

    结果如下:

    1c818aa5ea48e258d2a9e991c183fe0e.png

    除了run方法是在一个被自动取名为Thread-0的线程中其他的两个都在main方法中。

    但是我们不使用start方法来启动线程,我们直接调用run方法会怎么样呢?

    代码如下:

    public static voidmain(String[] args) {

    System.out.println("main方法被"+Thread.currentThread().getName()+"线程调用了");

    CurrentThreadText cu=newCurrentThreadText();

    cu.run();//我直接调用了run方法

    }

    结果:

    72fd63d1a3ac397f12106024516c72d9.png

    结果都是被main这个线程调用了,所以说想要启动多线程,就必须使用start方法而不是run方法。run方法就是和单线程一样按着顺序来调用,都在一个main线程中。

    二.isAlive()方法

    isAlive()方法人如其名意思就是“死没死啊?”,判断线程是否处于活跃状态

    列子如下:

    public class IsAliveText extendsThread{

    @Overridepublic voidrun(){

    System.out.print("调用run这个方法的线程为"+this.getName());if(this.isAlive()){

    System.out.println("这个线程是活跃的");

    }else{

    System.out.println("这个线程是不活跃的");

    }

    }public static voidmain(String[] args) {

    IsAliveText is=newIsAliveText();

    System.out.printf(String.format("开始时当前线程为%s,%s", is.getName(),is.isAlive()?("活跃"):("不活跃")));

    System.out.println();

    is.start();

    System.out.printf(String.format("结束时当前线程为%s,%s", is.getName(),is.isAlive()?("活跃"):("不活跃")));

    System.out.println();

    }

    }

    结果如下:

    c664f82201b9cc068c92867fe971c0cc.png

    三.sleep()方法

    sleep(n)方法是指让某个线程睡眠n个毫秒,比如

    public classThreadSleepText {public static void main(String[] args) throwsException {

    System.out.println("当前线程为"+Thread.currentThread().getName());

    Thread.sleep(5000);

    System.out.println("结束");

    }

    }

    程序会在5秒后结束。

    四.getID()方法

    过得线程的唯一标识

    展开全文
  • 宋波李晋李妙妍张悦 宋波李晋李妙妍张悦 * 宋波李晋李妙妍张悦 Java程序...宋波李晋李妙妍张悦 * 15.1 网络相关知识 Java为用户提供了完善网络功能 获取网络上各种资源 与服务器建立连接和通信 传递本地数据 这些功
  • java并发基础常用方法

    2019-07-24 15:27:50
    当切换进程时候我们不仅要切换指令序列,而且要切换内存映射表,但是线程之间切换只是在同一个内存映射表之间指令切换(在java中切换pc,虚拟机栈,本地方法栈,不切换堆和方法区),线程既保留了并发特点,...

    1、线程和进程 

    进程等于一个资源(即内存映射表)+多个指令执行序列,当切换进程的时候我们不仅要切换指令序列,而且要切换内存映射表,但是线程之间的切换只是在同一个内存映射表之间的指令切换(在java中切换pc,虚拟机栈,本地方法栈,不切换堆和方法区),线程既保留了并发的特点,又避免了线程切换的代价

     

    2、start和run

    调用start方法会新建一个线程,让这个新建的线程去调用run方法,而在当前线程中调用run方法,只是做为一个普通的方法调用,不能新建一个线程

     

    3、怎么优雅的终止线程

    不可用stop方法,因为stop方法太过暴力,强行把执行到一半的线程终止,可能会发生线程不一致的问题

    可以用一个violatile变量来标记什么时候需要终止线程,让线程退出

     

    4、wait和notify

    当在一个对象实例上调用wait方法后,当前线程就会在这个对象上等待,比如线程A调用了obj.wait()方法,线程A就会进入等待状态,等待到别的线程调用了obj.notify方法为止,obj就成为了多个线程之间的有效通信手段。wait和notify究竟是怎么工作的呢,具体来说如果一个线程调用了object.wait(),那么它就会进入object对象的等待队列。当notify被调用时,它就会从这个等待队列中随机选择一个线程进行唤醒。这个选择是不公平的,并不是先等待的线程会优先被选择,完全随机。还需要强调的是,wait和notify并不能随便调用,它们必须包含在对应的synchronized语句中。相似的还有与ReentrantLock相关联的Condition的await方法,当线程被中断时,也能跳出等待。而且能被signal()方法唤醒,必须在相应的lock和unlock语句块中。Object.wait()和Thread.sleep()都可以让线程等待若干时间,除了wait可以被唤醒之外,wait释放目标对象的锁,但是sleep不会释放任何资源。

    5、join和yield

    public class JoinMain{
    
        public volatile static int i = 0;
    
        public static class AddThread extends Thread{
            
                public void run(){
                    
                    for(i = 0;i < 1000000;i++);
    
            }
     
        }
    
       public static void main(String[] args){
    
        AddThread at = new AddThread();
        at.start();
        at.join();
    
        System.out.println(i);
    
        }
    
    }

    join可以让调用线程在当前线程对象上进行等待,如果不调用join,主线程可能会输出0或者是得到的很小的数,因为AddThread还没开始执行,主线程就把i的值输出了,但使用join方法后,主线程就会等待AddThread执行完毕,并跟着AddThread一起走。

    yield是指一旦调用,会使当前线程让出CPU,但让出CPU之后,还会进行CPU资源的争夺,能否再分配到就不一定了。

     

    6、守护线程

    守护线程是指在后台默默完成的一些系统性的服务,比如垃圾回收线程、JIT线程,与之相对应的是用户线程,用户进程就是系统的工作线程,当用户进程全部结束,这也意味着这个程序实际上无事可做了,当一个java应用内,只剩下守护线程时,Java虚拟机就会自然退出。比如下面的代码,当把t设置为守护线程时,当主线程结束后,程序就会自动结束,不然程序就会一直输出i am alive,需要注意的是setDaemon要设置在start()之前,不然t还是会被当成用户线程并且报异常IllegalThreadStateException

    package JMM;
    
    /**
     * @author: surepeng
     * @description:
     * @date: 2019/07/24
     **/
    public class DaemonDemo {
    
        public static class DaemonT extends Thread {
    
            public void run() {
    
                while (true) {
                    System.out.println("I am alive");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
            }
    
        }
    
        public static void main(String[] args) throws InterruptedException {
    
            Thread t = new DaemonT();
            t.setDaemon(true);
            t.start();
            Thread.sleep(2000);
        }
    
    }

     

    7、synchronized

      关键词synchronized的作用是实现线程间的同步,它的工作是对同步的代码加锁,使得每一次只能有一个线程加入同步代码块,从而保证线程间的安全性

    可以有多种用法:

    指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。

    直接用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。

    直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。

    对同一个对象instance加锁:

    public class AccountingSync implements Runnable{
    
           static AccountingSync instance = new AccountingSync();
    
           static int i = 0;
    
           public void run(){
            
                for(int j = 0;j<1000000;j++){
    
                    synchronized(instance){
    
                        i++;
                    }
    
                }
          }
    
    
        public static void main(String[] args) throws InterruptedException{
    
            Thread t1 = new Thread(instance);
            Thread t2 = new Thread(instance);
            t1.start();t2.start();
            t1.join();//为了避免t1和t2都没执行完主线程就执行完了
            t2.join();
            System.out.println(i);
    
       }
    
    }

    给同一个实例加锁,这里需要注意的是两个线程都指向同一个实例instance,如果是两个不同的对象,比如

    Thread t1 = new Thread(new AccountingSync());

    Thread t2 = new Thread(new AccountingSync());

    其实就是两把锁,就会导致无法预计的异常

    public class AccountingSync implements Runnable{
    
           static AccountingSync instance = new AccountingSync();
    
           static int i = 0;
    
           public synchronized void increase(){
    
                    i++;
        
           }
    
           public void run(){
            
                for(int j = 0;j<1000000;j++){
    
                    increase();
    
                }
          }
    
    
        public static void main(String[] args) throws InterruptedException{
    
            Thread t1 = new Thread(instance);
            Thread t2 = new Thread(instance);
            t1.start();t2.start();
            t1.join();//为了避免t1和t2都没执行完主线程就执行完了
            t2.join();
            System.out.println(i);
    
       }
    
    }
     

    给同一个类加锁:

    如果将上面的increase()方法变成static的,即使两个线程指向不同的Runnable对象,但由于方法快请求的是当前类的锁,而非当前实例,因此,线程间还是可以正常同步。

    public class AccountingSync implements Runnable{
    
           static AccountingSync instance = new AccountingSync();
    
           static int i = 0;
    
           public static synchronized void increase(){
    
                    i++;
        
           }
    
           public void run(){
            
                for(int j = 0;j<1000000;j++){
    
                    increase();
    
                }
          }
    
    
        public static void main(String[] args) throws InterruptedException{
    
            Thread t1 = new Thread(new AccountingSync());
            Thread t2 = new Thread(new AccountingSync());
            t1.start();t2.start();
            t1.join();//为了避免t1和t2都没执行完主线程就执行完了
            t2.join();
            System.out.println(i);
    
       }
    
    }
     

     

    展开全文
  • Java异常常用方法

    2019-03-01 18:35:00
    getLocalizedMessage()方法返回Exception的本地化描述。getMessage()方法返回Exception的详细消息字符串 转载于:https://www.cnblogs.com/z-y-x/p/10458145.html

    getLocalizedMessage()方法返回 Exception的本地化描述。

    getMessage()方法返回 Exception的详细消息字符串

    转载于:https://www.cnblogs.com/z-y-x/p/10458145.html

    展开全文
  • 本文为在 32 位 Windows 平台上实现 Java 本地方法提供了实用的示例、步骤和准则。这些示例包括传递和返回常用的数据类型。 本文中的示例使用 Sun Microsystems 公司创建的 Java Development Kit (JDK) 版本 1.1.6 ...
  • 本文提供调用本地 C 代码的 Java 代码示例,包括传递和返回某些常用的数据类型。本地方法包含在特定于平台的可执行文件中。就本文中的示例而言,本地方法包含在 Windows 32 位动态链接库 (DLL) 中。 不过我要提醒您...
  • java 常用api

    2017-05-25 16:59:50
    spring,mybatis,hibernate,springMvc,jquery1.8,think in Java第五版,还有本地测试借口的方法的小公举wsCaller等等。
  • java常用的基本类 1.Object类 Object类是所有类的基类,所有的类都继承Object类 常用方法 equals(Object)-> boolean :比较两个对象的地址(内部为==),需要在继承的类中根据自己的规则重写 hasCode()...
  • 给定的日期和时间为美国太平洋时区的本地时间 2001-07-04 12:08:56。日期和时间模式结果"yyyy.MM.dd G 'at' HH:mm:ss z"2001.07.04 AD at 12:08:56 PDT"EEE, MMM d, ''yy"Wed, Jul 4, '01"h:mm a"12:08 PM"hh 'o''...
  • 使用sheet以下方法可以获取到Excel中所有合并单元格信息,读取到单元格值为空时,可以通过判断它是否在合并单元格范围内区分。 public voidgetExcelMergedRegins(Sheet sheet) {//获取合并单元格范围 int ...
  • java常用介绍

    千次阅读 2013-09-23 23:44:41
    1. 常用类有:java.util包下类 日期类Date, 本地处理类Locale, 日历处理类Calendar以及DateFormat和SimpleDateFormat类 2. Date方法介绍: a) Date d = new Date() b) d.getyear() + 1900,为了方便计数,...
  • 使用sheet以下方法可以获取到Excel中所有合并单元格信息,读取到单元格值为空时,可以通过判断它是否在合并单元格范围内区分。 public voidgetExcelMergedRegins(Sheet sheet) {//获取合并单元格范围 int ...
  • Java常用

    2015-10-15 10:08:55
    一、Object类 ...native本地,这是一个用C/C++编写的本地方法,运行在本地方法栈。   常见方法 1、public int hashCode() 返回该对象的哈希码值。支持此方法是为了提高哈希表的性能。 2、public St
  • Java常用类库

    2020-08-20 00:40:54
    ==号和equals作用****获取功能方法**转换功能方法分割功能方法String 类练习字符串反转Object类native 本地方法https://www.cnblogs.com/KingIceMou/p/7239668.htmltoString() 方法toString()方法重写...
  • 本文为在 32位 Windows 平台上实现 Java 本地方法提供了实用的示例、步骤和准则。这些示例包括传递和返回常用的数据类型。 本文中的示例使用 Sun Microsystems公司创建的 JavaDevelopmentKit (JDK)版本 ...
  • java常用实用类

    2020-08-30 19:20:55
    Data类在java.util包中,它无参构造方法创建对象可以获取本地当前时间。用Data构造方法Data(long time)创建对象表示相对1970年1月1日0点(GMT)时间。System类静态方法currentTimeMillis()可获取系统...
  • Java通过JNI调用本地C/C++程序--常用示例  关于java调用本地c/c++程序,流程及简单示例可以参考《Java通过JNI调用本地C或C++程序》,下面列举下常用到示例。 1创建java类,及native方法 package ...
  • 本地方法栈4.堆5.方法区(1) 方法区和永久代关系(2 )常用参数(3 )为什么要将永久代 (PermGen) 替换为元空间 (MetaSpace) 呢?6.运行时常量池7.直接内存Java代码执行过程汇编语言,机器语言,高级语言关系JVM架构...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 834
精华内容 333
关键字:

java常用的本地方法

java 订阅