精华内容
下载资源
问答
  • ubuntu(linux)跟踪指定进程的线程执行状态的方法 新建一个用于测试的py文件,内容如下 # coding: utf-8 import threading import time import os import ctypes def func(arg): while True: time....

    ubuntu(linux)跟踪指定进程的线程执行状态的方法
    新建一个用于测试的py文件,内容如下

    
    # coding: utf-8
    import threading
    import time
    import os
    import ctypes
    def func(arg):
        while True:
            time.sleep(1)
            print('thread:{}, arg={}, pid={}, ppid={}'.format(threading.get_ident(), arg,os.getpid(),   ctypes.CDLL('libc.so.6').syscall(186)))
        return 0
    
    if __name__ == '__main__':
        threading.Thread(target=func, name='eat', args=(1,),daemon=True).start()
        threading.Thread(target=func, name='run', args=(2,),daemon=True).start()
    
        while True:
            time.sleep(1)
    
    
    

    1、首先使用ps -aux | grep “PROGRAM_WORD”命令去过滤你要查看的进程
    获取进程id,如下图:
    在这里插入图片描述

    2、使用 ps -T -p 27850
    在这里插入图片描述

    3、使用 strace -p 27851
    在这里插入图片描述

    注意:如果在docker中无法执行strace命令,则启动docker时增加–priveleged参数即可,例如:docker exec --priveleged -it CONTAINER_NAME bash

    另外,本文提供了使用python获取线程id的方法,使用ctypes加载C标准库,然后再通过系统调用获取线程id。

    展开全文
  • Android: 获取当前线程状态

    万次阅读 2014-10-07 11:18:01
    看代码学知识之(1) 获取当前线程状态() 缘起  今天看到有一个工具类中有一句: String msgToPrint = Thread.currentThread().getStackTrace()[3] .getMethodName();  输出的结果很简单,...

    看代码学知识之(1) 获取当前线程状态(http://www.cnblogs.com/mengdd/p/3285592.html)


    缘起

      今天看到有一个工具类中有一句:

    String msgToPrint = Thread.currentThread().getStackTrace()[3]
                        .getMethodName();

      输出的结果很简单,就是调用时的方法名。

     

     

    文档:

      其中使用的Thread类的第一个方法:

    public static Thread currentThread()

      返回当前线程对象。

     

      第二个方法:(阅读Java SE的文档:)

    public StackTraceElement[] getStackTrace()

      返回一个堆栈轨迹元素的数组,代表了这个线程的堆栈情况。

      如果:1.这个线程没有被开启;2.这个线程被开启了但是没有被系统运行过(因为线程运行是需要根据一定规律轮换的);3.这个线程结束了。

      这三种情况下getStackTrace()返回的数组长度为0。

     

      如果返回的数组长度不为0,那么数组的第一个元素代表栈顶元素,即是这个调用序列中最recent的方法。

      数组的最后一个元素代表栈底元素,即调用序列中最远的一个元素。

     

     

    程序实测——Java程序

      写一个测试类,main方法如下:

    复制代码
    public static void main(String[] args) {
            StackTraceElement[] stackTraceElements = Thread.currentThread()
                    .getStackTrace();
    
            System.out.println("The stackTraceElements length: "
                    + stackTraceElements.length);
            for (int i = 0; i < stackTraceElements.length; ++i) {
                System.out.println("\n\n----  the " + i + " element  ----");
                System.out.println("toString: " + stackTraceElements[i].toString());
                System.out.println("ClassName: "
                        + stackTraceElements[i].getClassName());
                System.out.println("FileName: "
                        + stackTraceElements[i].getFileName());
                System.out.println("LineNumber: "
                        + stackTraceElements[i].getLineNumber());
                System.out.println("MethodName: "
                        + stackTraceElements[i].getMethodName());
            }
    
            //printStackInfos();
        }
    复制代码

      

      执行后输出:

    复制代码
    The stackTraceElements length: 2
    
    
    ----  the 0 element  ----
    toString: java.lang.Thread.getStackTrace(Unknown Source)
    ClassName: java.lang.Thread
    FileName: null
    LineNumber: -1
    MethodName: getStackTrace
    
    
    ----  the 1 element  ----
    toString: com.mengdd.time.StackTest.main(StackTest.java:7)
    ClassName: com.mengdd.time.StackTest
    FileName: StackTest.java
    LineNumber: 7
    MethodName: main
    复制代码

     

      如果再用一个私有方法:

    复制代码
    package com.mengdd.time;
    
    public class StackTest {
    
        public static void main(String[] args) {
            StackTraceElement[] stackTraceElements = Thread.currentThread()
                    .getStackTrace();
    
            System.out.println("The stackTraceElements length: "
                    + stackTraceElements.length);
            for (int i = 0; i < stackTraceElements.length; ++i) {
                System.out.println("\n\n----  the " + i + " element  ----");
                System.out.println("toString: " + stackTraceElements[i].toString());
                System.out.println("ClassName: "
                        + stackTraceElements[i].getClassName());
                System.out.println("FileName: "
                        + stackTraceElements[i].getFileName());
                System.out.println("LineNumber: "
                        + stackTraceElements[i].getLineNumber());
                System.out.println("MethodName: "
                        + stackTraceElements[i].getMethodName());
            }
    
            // 用一个私有方法,输出调用堆栈的信息
            printStackInfos();
        }
    
        private static void printStackInfos() {
            StackTraceElement[] stackTraceElements = Thread.currentThread()
                    .getStackTrace();
    
            System.out.println("\n\nCalled in printStackInfos() method!!!!!!!");
            System.out.println("The stackTraceElements length: "
                    + stackTraceElements.length);
            for (int i = 0; i < stackTraceElements.length; ++i) {
                System.out.println("\n\n----  the " + i + " element  ----");
                System.out.println("toString: " + stackTraceElements[i].toString());
                System.out.println("ClassName: "
                        + stackTraceElements[i].getClassName());
                System.out.println("FileName: "
                        + stackTraceElements[i].getFileName());
                System.out.println("LineNumber: "
                        + stackTraceElements[i].getLineNumber());
                System.out.println("MethodName: "
                        + stackTraceElements[i].getMethodName());
            }
    
        }
    
    }
    复制代码

     

      则输出结果如下:

    复制代码
    The stackTraceElements length: 2
    
    
    ----  the 0 element  ----
    toString: java.lang.Thread.getStackTrace(Unknown Source)
    ClassName: java.lang.Thread
    FileName: null
    LineNumber: -1
    MethodName: getStackTrace
    
    
    ----  the 1 element  ----
    toString: com.mengdd.time.StackTest.main(StackTest.java:7)
    ClassName: com.mengdd.time.StackTest
    FileName: StackTest.java
    LineNumber: 7
    MethodName: main
    
    
    Called in printStackInfos() method!!!!!!!
    The stackTraceElements length: 3
    
    
    ----  the 0 element  ----
    toString: java.lang.Thread.getStackTrace(Unknown Source)
    ClassName: java.lang.Thread
    FileName: null
    LineNumber: -1
    MethodName: getStackTrace
    
    
    ----  the 1 element  ----
    toString: com.mengdd.time.StackTest.printStackInfos(StackTest.java:30)
    ClassName: com.mengdd.time.StackTest
    FileName: StackTest.java
    LineNumber: 30
    MethodName: printStackInfos
    
    
    ----  the 2 element  ----
    toString: com.mengdd.time.StackTest.main(StackTest.java:25)
    ClassName: com.mengdd.time.StackTest
    FileName: StackTest.java
    LineNumber: 25
    MethodName: main
    复制代码

      可以看到加了一个私有方法之后,返回的堆栈元素就多了一个,并且它的位置在调用它的方法和被它调用的方法之间

      可是为什么我看的程序里面用的是数组的第三个元素呢?——因为我看的是Android程序。

      看了代码才知道虽然Android的SDK里面包含了很多Java的类并且包名和类名都相同,但是具体的代码实现有可能是不同的。

     

     

    程序实测——Android程序

      写了如上相同的Android版程序:

    复制代码
    package com.example.helloandroidstack;
    
    import android.os.Bundle;
    import android.app.Activity;
    import android.view.Menu;
    
    public class HelloStackActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_hello_stack);
    
            StackTraceElement[] stackTraceElements = Thread.currentThread()
                    .getStackTrace();
            System.out.println("Called in onCreate() method!!!!!!!");
            System.out.println("The stackTraceElements length: "
                    + stackTraceElements.length);
            for (int i = 0; i < stackTraceElements.length; ++i) {
                System.out.println("----  the " + i + " element  ----");
                System.out.println("toString: " + stackTraceElements[i].toString());
                System.out.println("ClassName: "
                        + stackTraceElements[i].getClassName());
                System.out.println("FileName: "
                        + stackTraceElements[i].getFileName());
                System.out.println("LineNumber: "
                        + stackTraceElements[i].getLineNumber());
                System.out.println("MethodName: "
                        + stackTraceElements[i].getMethodName());
            }
    
            printStackInfos();
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.hello_stack, menu);
            return true;
        }
    
        private void printStackInfos() {
            StackTraceElement[] stackTraceElements = Thread.currentThread()
                    .getStackTrace();
    
            System.out.println("Called in printStackInfos() method!!!!!!!");
            System.out.println("The stackTraceElements length: "
                    + stackTraceElements.length);
            for (int i = 0; i < stackTraceElements.length; ++i) {
                System.out.println("----  the " + i + " element  ----");
                System.out.println("toString: " + stackTraceElements[i].toString());
                System.out.println("ClassName: "
                        + stackTraceElements[i].getClassName());
                System.out.println("FileName: "
                        + stackTraceElements[i].getFileName());
                System.out.println("LineNumber: "
                        + stackTraceElements[i].getLineNumber());
                System.out.println("MethodName: "
                        + stackTraceElements[i].getMethodName());
            }
    
        }
    
    }
    复制代码

      部分输出截图如下:

      在onCreate()中调用的时候:


      把语句都另一个方法中调用的时候:

     

      可以清楚地看到,当获取stack trace的语句放在另一个方法(工具类方法)中的时候,数组索引为3的元素可以找到该工具类方法的调用地点。

      在此例中,找到的是onCreate()方法中的第32行。


    ____________________________________________________________________________________________

    android debug, print class name, line number (http://blog.csdn.net/yuxiaohui78/article/details/38076547)

    在Android调试的时候,有时候需要打印指定的行号和类名。

    下面是一个调试log的类。

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    1. package com.project.mocha_doctor.common;  
    2.   
    3. import android.util.Log;  
    4.   
    5. public class SmabDebug {  
    6.       
    7.     private final static boolean DEBUG = true;  
    8.     private final static String TAG = "YXH";  
    9.     private final static int pos = 3;  
    10.       
    11.     public static void log(String message)  
    12.     {  
    13.         if (DEBUG)  
    14.         {  
    15.             String fullClassName = Thread.currentThread().getStackTrace()[pos].getClassName();              
    16.             String className = fullClassName.substring(fullClassName.lastIndexOf(".") + 1);  
    17.             String methodName = Thread.currentThread().getStackTrace()[pos].getMethodName();  
    18.             int lineNumber = Thread.currentThread().getStackTrace()[pos].getLineNumber();  
    19.   
    20.             Log.i(TAG + " - "  + className + "." + methodName + "():" + lineNumber, message);  
    21.         }  
    22.     }  
    23.       
    24.       
    25. /* 
    26. 0   VMStack.getThreadStackTrace() 
    27. 1   Thread.getStackTrace() 
    28. 2   SmabDebug.printStack() 
    29. 3   HttpRequestTask.onPostExecute() 
    30. 4   HttpRequestTask.onPostExecute() 
    31. 5   AsyncTask.finish() 
    32. 6   AsyncTask.access$600() 
    33. 7   AsyncTask$InternalHandler.handleMessage() 
    34. 8   Handler.dispatchMessage() 
    35. 9   Looper.loop() 
    36. 10  ActivityThread.main() 
    37. 11  Method.invokeNative() 
    38. 12  Method.invoke() 
    39. 13  ZygoteInit$MethodAndArgsCaller.run() 
    40. 14  ZygoteInit.main() 
    41. 15  NativeStart.main() 
    42.  
    43.  If the value = 3, it means the caller Class. 
    44.  */  
    45.       
    46.     public static void printStack (){  
    47.         int deep = Thread.currentThread().getStackTrace().length;  
    48.           
    49.         for (int i = 0; i < deep; i ++){  
    50.          String fullClassName = Thread.currentThread().getStackTrace()[i].getClassName();              
    51.          String className = fullClassName.substring(fullClassName.lastIndexOf(".") + 1);  
    52.          String methodName = Thread.currentThread().getStackTrace()[i].getMethodName();  
    53.          Log.i(TAG,  className + "." + methodName + "()");  
    54.         }  
    55.     }  
    56. }  
    调用的时候只需要简单的

    SmabDebug.log ( "Status code ---->" + codeStr);

    log输出为如下, 不会输出这个类名。

    I/YXH - ServerTimeSyncUp$GETRequestListener.ServerResponse():86(13348): Status code----->145



    展开全文
  • Java如何获取当前线程

    万次阅读 2018-07-05 08:26:48
    Java 中经常会遇到要获取当前线程的情况,这时一般我们就会通过Thread.currentThread()来获取,接下去就看看执行该语句在 JVM 中做了什么吧。 简单例子 以下是一个简单的例子,获取当前线程并打印线程名称,输出...

    前言

    Java 中经常会遇到要获取当前线程的情况,这时一般我们就会通过Thread.currentThread()来获取,接下去就看看执行该语句在 JVM 中做了什么吧。

    简单例子

    以下是一个简单的例子,获取当前线程并打印线程名称,输出是”main”,即主线程。

    public class CurrentThreadTest {
    
        public static void main(String[] args) {
            Thread t = Thread.currentThread();
            System.out.println(t.getName());
        }
    
    }

    currentThread方法

    在 Thread 类中,currentThread是一个静态且本地方法。

    public static native Thread currentThread();

    Thread.c

    Java 层声明的本地方法对应实现在 Thread.c 中,currentThread是一个注册到 JVM 中的方法,它与 JVM 中的JVM_CurrentThread函数绑定了,所以实现逻辑在JVM_CurrentThread函数里。逻辑为:
    * JVMWrapper("JVM_CurrentThread")用于调试。
    * 通过thread->threadObj()获取 oop,这里的 thread 是在JNI_ENTRY宏中获取到的,详细情况可参考后面的JNI_ENTRYJNI_END宏。
    * 调用JNIHandles::make_local函数

    #define THD "Ljava/lang/Thread;"
    
    static JNINativeMethod methods[] = {
        ...
        {"currentThread",    "()" THD,     (void *)&JVM_CurrentThread},
        ...
    };
    
    JVM_ENTRY(jobject, JVM_CurrentThread(JNIEnv* env, jclass threadClass))
      JVMWrapper("JVM_CurrentThread");
      oop jthread = thread->threadObj();
      assert (thread != NULL, "no current thread!");
      return JNIHandles::make_local(env, jthread);
    JVM_END

    make_local函数中主要看thread_from_jni_environment函数,它用于获取当前线程,它的逻辑为JavaThread *thread_from_jni_env = (JavaThread*)((intptr_t)env - in_bytes(jni_environment_offset()));,即直接通过地址偏移来做减法计算得到JavaThread*,这是因为 JavaThread 对象包含了 JNIEnv 对象属性,所以可以通过JNIEnv*与偏移做减法来算出JavaThread*。最后还要检查线程是否已经终止状态,没有终止才返回该线程对象。

    获取到JavaThread*对象后,分配句柄并将 oop 赋给句柄,并且转成 Java 层的对象 jobject。

    jobject JNIHandles::make_local(JNIEnv* env, oop obj) {
      if (obj == NULL) {
        return NULL;                
      } else {
        JavaThread* thread = JavaThread::thread_from_jni_environment(env);
        assert(Universe::heap()->is_in_reserved(obj), "sanity check");
        return thread->active_handles()->allocate_handle(obj);
      }
    }
    
    static JavaThread* thread_from_jni_environment(JNIEnv* env) {
        JavaThread *thread_from_jni_env = (JavaThread*)((intptr_t)env - in_bytes(jni_environment_offset()));
        if (thread_from_jni_env->is_terminated()) {
          thread_from_jni_env->block_if_vm_exited();
          return NULL;
        } else {
          return thread_from_jni_env;
        }
      }

    JNI_ENTRYJNI_END

    这两个宏将共同的部分都抽离出来了。其中JNI_END比较简单,就两个结束大括号。

    #define JNI_ENTRY(result_type, header)  JNI_ENTRY_NO_PRESERVE(result_type, header)    WeakPreserveExceptionMark __wem(thread);
    
    #define JNI_END } }

    JNI_ENTRY主要逻辑:
    * 获取当前执行线程 JavaThread 指针对象。
    * 创建 ThreadInVMfromNative 对象。
    * TRACE_CALL ,这里什么都不干。
    * 创建 HandleMarkCleaner 对象。
    * 将 thread 赋值给 Exceptions 中的 THREAD。
    * 校验栈对齐。
    * 创建 WeakPreserveExceptionMark 对象。

    #define JNI_ENTRY_NO_PRESERVE(result_type, header)                   \
    extern "C" {                                                         \
      result_type JNICALL header {                                       \
        JavaThread* thread=JavaThread::thread_from_jni_environment(env); \
        assert( !VerifyJNIEnvThread || (thread == Thread::current()), "JNIEnv is only valid in same thread"); \
        ThreadInVMfromNative __tiv(thread);                              \
        debug_only(VMNativeEntryWrapper __vew;)                          \
        VM_ENTRY_BASE(result_type, header, thread)
    
    #define VM_ENTRY_BASE(result_type, header, thread)                   \
      TRACE_CALL(result_type, header)                                    \
      HandleMarkCleaner __hm(thread);                                    \
      Thread* THREAD = thread;                                           \
      os::verify_stack_alignment();      

    ————-推荐阅读————

    我的2017文章汇总——机器学习篇

    我的2017文章汇总——Java及中间件

    我的2017文章汇总——深度学习篇

    我的2017文章汇总——JDK源码篇

    我的2017文章汇总——自然语言处理篇

    我的2017文章汇总——Java并发篇


    跟我交流,向我提问:

    这里写图片描述

    公众号的菜单已分为“读书总结”、“分布式”、“机器学习”、“深度学习”、“NLP”、“Java深度”、“Java并发核心”、“JDK源码”、“Tomcat内核”等,可能有一款适合你的胃口。

    为什么写《Tomcat内核设计剖析》

    欢迎关注:

    这里写图片描述

    展开全文
  • 产生一个线程: HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD描述施行与这一新线程的security属性,NULL表示使用缺省值,在windows 95中忽略该参数 DWORD dwStackSize, // initial ...

    产生一个线程:

    HANDLE CreateThread(
      LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD描述施行与这一新线程的security属性,NULL表示使用缺省值,在windows 95中忽略该参数
      DWORD dwStackSize,                        // initial stack size新线程拥有的堆栈大小,0表示缺省大小,1MB
      LPTHREAD_START_ROUTINE lpStartAddress,    // thread function  函数指针
      LPVOID lpParameter,                       // thread argument  传递到线程函数的参数
      DWORD dwCreationFlags,                    // creation option  允许产生一个暂时挂起的线程,默认为立即运行
      LPDWORD lpThreadId                        // thread identifier  //新的线程ID会被传回到这里
    );



    第一个使用线程范例:
    //多线程出现的执行混乱问题


    #define WIN32_LEAN_AND_MEAN
    #include<stdio.h>
    #include<stdlib.h>
    #include<windows.h>
    
    
    DWORD WINAPI ThreadFunc(LPVOID); //线程标准函数形式
    //#define  WINAPI _stdcall
    
    
    int main()
    {
      HANDLE hThrd;
      DWORD threadId;
      int i;
      for(i=0;i<5;i++)
      {
    	  hThrd=CreateThread(NULL,0,ThreadFunc,(LPVOID)i,0,&threadId);
         //返回一个核心对象hThrd
    	  if(hThrd)
    	  {
    		  printf("Thread Start %d\n",i);
    		  CloseHandle(hThrd);
    	  }
      }
    
    
      Sleep(2000); //等待这些线程完成,不加这句,主线程将结束,其他线程将无法完成
      return EXIT_SUCCESS;
    }
    
    
    DWORD WINAPI ThreadFunc(LPVOID n)
    {
      int i;
      for(i=0;i<10;i++)
      {
    	  printf("%d%d%d%d%d%d%d%d\n",n,n,n,n,n,n,n,n);
      }
      return 0;
    }
    




    核心对象:CreateThread()返回的handle被称为一个核心对象(kernel object).其和所谓的GDI对象,如画笔、画刷或DC差不多,前者由KERNEL32.DLL管理,后者由GDI32.DLL管理。所谓handle就是一个


    指针,指向操作系统内存空间的某样东西,那东西不允许你直接 取得。
    Win32核心对象清单:
    1.进程(processes),线程(threads),文件(files),事件(events),信号量(semaphores),互斥器(mutexes),管道(Pipes,分为named和anonymous两种)
    这些核心对象可以用来整合许多的线程或进程。
    GDI对象和核心对象的主要区别:GDI的对象有单一拥护者,不是进程就是线程。核心对象可以有一个以上的拥有者,甚至可以跨进程。


    BOOL CloseHandle(
      HANDLE hObject   // handle to object
    );
    

    不关闭可能导致资源泄露。不可以依赖“因线程的结束而清理所有被这一线程产生的核心对象”。许多对象,如文件,是被进程所拥有,而非线程拥有,在进程结束之前不能够清理它们。

    线程对象与线程的不同:
    线程的handle是指向“线程核心对象”,而不是指向线程本身。当调用CloseHandle()并给一个线程handle时候,就是吧引用计数减1.如果该值变为0,对象会自动被操作系统销毁。

    判断线程是否结束:
    BOOL GetExitCodeThread(
      HANDLE hThread,      // handle to the thread
      LPDWORD lpExitCode   // termination status
    );


    如果线程结束,结束代码会被放在lpExitCode参数中带回来。如果没有结束,lpExitCode的值是STILL_ACTIVE.
    如果成功,返回True,否则返回False;
    GetExitCodeThread将传回线程函数ThreadFunc的返回值。
    GetExitCodeThread等待一个线程的结束,但这并不是最好的方法


    第二个线程范例:
    //示例GetExitCodeThread的用法,获取线程的状态
    #define WIN32_LEAN_AND_MEAN
    #include<stdio.h>
    #include<stdlib.h>
    #include<windows.h>
    #include<conio.h>
    DWORD WINAPI ThreadFunc(LPVOID); //线程标准函数形式
    
    
    int main()
    {
    	
      HANDLE hThrd1;
      HANDLE hThrd2;
      DWORD exitCode1=0;
      DWORD exitCode2=0;
    
    
      DWORD threadId;
    
    
      hThrd1=CreateThread(NULL,0,ThreadFunc,(LPVOID)1,0,&threadId);
    
    
      if(hThrd1)
    	  printf("Thread 1 launched \n");
    
    
      hThrd2=CreateThread(NULL,0,ThreadFunc,(LPVOID)2,0,&threadId);
      if(hThrd2)
    	  printf("Thread 2 launched \n");
    
    
      for(;;)
      {
    	  printf("Press any key to exit..\n");
    	  getch();
    	  	  //GetExitCodeThread等待一个线程的结束,但这并不是最好的方法
    	  GetExitCodeThread(hThrd1,&exitCode1); //GetExitCodeThread将传回线程函数ThreadFunc的返回值
    	  GetExitCodeThread(hThrd2,&exitCode2);
    
    
    	  if(exitCode1==STILL_ACTIVE)
    		  puts("Thread 1 is still running ...");
    	  if(exitCode2==STILL_ACTIVE)
    		  puts("Thread 2 is still running ...");
    
    
    	  if(exitCode1!=STILL_ACTIVE&&exitCode2!=STILL_ACTIVE)
    		  break;
    
    
    
    
      }
      CloseHandle(hThrd1);
      CloseHandle(hThrd2);
      printf("Thread 1 returned %d\n",exitCode1);
      printf("Thread 2 returned %d\n",exitCode2);
    
    
     return  EXIT_SUCCESS;
    
    
    
    
    
    
    }
    DWORD WINAPI ThreadFunc(LPVOID n)
    {
    	Sleep((DWORD)n*1000*2);
    	return (DWORD)n*2;
    }
    


    结束一个线程:

    前面是靠线程函数的结束而结束线程。有时候需要更强制性的手法结束一个线程要用ExitThread();
    VOID ExitThread(
      DWORD dwExitCode   // exit code for this thread 指示此线程之结束代码
    );
    



    它可以在任何时候被调用并且绝对不会返回。任何代码若放在此行之下,保证不会被执行。


    如果线程还在运行而我的程序的结束了,会怎么样??
    结束主线程:程序启动后就执行一个线程称为主线程,主线程有两个特点,第一,负责GUI程序中的主消息循环。第二,这一线程的结束(不论是因为返回或因为调用了ExitThread())会使程序中的所有


    线程都被强迫结束,程序也因此结束。其他线程没有机会做清理工作。故在main或WinMain结束之前,总是先等待所有的线程都结束。
    建议在主线程中不要调用ExitThread();


    第三个线程范例:怎么结束一个线程
    #define WIN32_LEAN_AND_MEAN
    #include<stdio.h>
    #include<stdlib.h>
    #include<windows.h>
    DWORD WINAPI ThreadFunc(LPVOID); //线程标准函数形式
    void AnotherFunc(void);
    
    
    int main()
    {
     HANDLE hThrd;
     DWORD exitCode=0;
     DWORD threadId;
     hThrd=CreateThread(NULL,0,ThreadFunc,(LPVOID)1,0,&threadId);
    
    
      if(hThrd)
    	  printf("Thread launched.. \n");
    
    
      for(;;)
      {
    	  bool rc;
    	  rc=GetExitCodeThread(hThrd,&exitCode);
    	  if(rc&&exitCode!=STILL_ACTIVE)
    		  break;
      }
    
    
      CloseHandle(hThrd);
      printf("Thread  returned %d\n",exitCode);
       return  EXIT_SUCCESS;
    
    
    
    
    }
    
    
    DWORD WINAPI ThreadFunc(LPVOID n)
    {
      printf("Thread running ..\n");
      AnotherFunc(); //调用一个函数,退出该线程
      return 0;
    }
    
    
    void AnotherFunc()
    {
    printf("About to exit Thread ..\n");
    ExitThread(4);
    printf("This will never print ..\n"); //这一行不会被打印
    }
    






    /****************错误处理*********************/
    可以调用GetLastError获得描述
    什么是MTVERIFY?
    它是一个宏,这个宏内部记录并解释Win32 GetLastError()的结果。如果Win32函数失败,MTVERIFY()会打印一段简短的文字说明。


    如何使用MTVERIFY的范例:
    错误处理函数
    //示例错误处理
    #define WIN32_LEAN_AND_MEAN
    #include<stdio.h>
    #include<stdlib.h>
    #include<windows.h>
    //MTVERIFY宏进入
    #include "MtVerify.h"
    DWORD WINAPI ThreadFunc(LPVOID);
    
    
    int main()
    {
      HANDLE hThrd;
     DWORD exitCode=0;
     DWORD threadId;
     MTVERIFY(hThrd=CreateThread(NULL,0,ThreadFunc,(LPVOID)1,0,&threadId));
    
    
    if(hThrd)
    	  printf("Thread launched.. \n");
    
    
    MTVERIFY(CloseHandle(hThrd));
    
    
    for(;;)
      {
    	  bool rc;
    	  MTVERIFY(rc=GetExitCodeThread(hThrd,&exitCode));
    	  if(rc&&exitCode!=STILL_ACTIVE)
    		  break;
    
    
      }
    printf("Thread  returned %d\n",exitCode);
    	return EXIT_SUCCESS;
    
    
    }
    
    
    DWORD WINAPI ThreadFunc(LPVOID n)
    {
      printf("Thread running ..\n");
      return 0;
    }
    
    
    
    
    /**  
    * MtVerify.h  
    *  
    * Error handling for applications in  
    * "Multitheading Applications in Win32"  
    *  
    * The function PrintError() is marked as __inline so that it can be  
    * included from one or more C or C++ files without multiple definition  
    * errors. For the examples in this book, this works fine.  
    * To use the PrintError() in an application, it should be taken out,  
    * placed in its own source file, and the "__inline" declaration removed  
    * so the function will be globally available.  
    */  
    #pragma comment( lib, "USER32" )   
    #include <stdlib.h>   
    #include <crtdbg.h>   
    #define MTASSERT(a) _ASSERTE(a)   
    // 宏定义 __FILE__ 与__LINE__都是预处理符号提供错误信息的描述   
    // 如果a返回FALSE就执行PrintError函数   
    #define MTVERIFY(a) if (!(a)) PrintError(#a,__FILE__,__LINE__,GetLastError())   
    __inline void PrintError(LPSTR linedesc, LPSTR filename, int lineno, DWORD errnum)   
    {   
    	LPSTR lpBuffer;   
    	char errbuf[256];   
    #ifdef _WINDOWS   
    	char modulename[MAX_PATH];   
    #else // _WINDOWS   
    	DWORD numread;   
    #endif // _WINDOWS   
    	// 把从GetLastError()返回的错误码转化为错误信息    
    	FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER   
    		| FORMAT_MESSAGE_FROM_SYSTEM,   
    		NULL,   
    		errnum,   
    		LANG_NEUTRAL,   
    		(LPTSTR)&lpBuffer,   
    		0,   
    		NULL );   
    	wsprintfA(errbuf, "\nThe following call failed at line %d in %s:\n\n"  
    		" %s\n\nReason: %s\n", lineno, filename, linedesc, lpBuffer);   
    	// 如果是console程序就输出信息到控制台上
    #ifndef _WINDOWS   
    	WriteFile(GetStdHandle(STD_ERROR_HANDLE), errbuf, strlen(errbuf), &numread, FALSE );   
    	// 等待3秒钟是为了使用者看到出错信息   
    	Sleep(3000);   
    	// 如果是窗口程序就一弹出对话框的形式输出错误信息
    #else   
    	// 当前exe文件的全路径   
    	GetModuleFileName(NULL, modulename, MAX_PATH);   
    	// 置弹出窗口在最上层以免被忽略   
    	MessageBox(NULL, errbuf, modulename, MB_ICONWARNING|MB_OK|MB_TASKMODAL|MB_SETFOREGROUND);   
    #endif   
    	// 把结束代码EXIT_FAILURE 交给操作系统
    	exit(EXIT_FAILURE);   
    }  



    多线程综合实例:后台打印,建立一个Win32 Application 

    /*多线程后台打印范例*/
    
    
    /******************************/
    /*
     * 
     *
     * Sample code for "Multithreading Applications in Win32"
     * This is from Chapter 2, Listing 2-3
     *
     * Demonstrates background printing
     */
    
    #define WIN32_LEAN_AND_MEAN
    #include <stdio.h>
    #include <stdlib.h>
    #include <windows.h>
    #include <windowsx.h>
    #include <commdlg.h>
    #include "resource.h"
    #include "MtVerify.h"
    
    //
    // Macro definitions
    //
    #define WM_SHOWBITMAP   WM_APP
    
    #define MAX_PRINT_JOBS  64
    
    //
    // Structures
    //
    typedef struct
    {   // Information passed to background thread for printing
        HWND hDlg;
        HWND hWndParent;
        HDC hDc;
        BOOL bPrint;    // TRUE if printing;
        char szText[256];
    } ThreadPrintInfo;
    
    //
    // Global variables
    //
    HANDLE hInst;
    HBITMAP gbmpDisplay;
    RECT gDisplayRect;
    
    int gNumPrinting = 0;
    
    // Handle to each created thread
    HANDLE gPrintJobs[64]; //保存已经创建的线程
    
    // Height of bitmap returned by DrawText
    int iHeight;
    
    // HWND of the dialog so other threads can find it.
    HWND hDlgMain;
    
    
    //
    // Function declarations
    //
    int APIENTRY WinMain(HINSTANCE hInstance/*当前程序运行实例的句柄,每个程序可以运行多个实例*/,
    				   HINSTANCE hPrevInstance, /*当前实例前一个实例的句柄 ,win32下为NULL*/
    				   LPSTR lpCmdLine, /*指定传递给命令行的参数*/
    				   int nCmdShow/*指定程序窗口应该如何显示,如最大化等*/);
    LRESULT CALLBACK MainWndProc(HWND hWnd/*标志接受消息的具体窗口*/, unsigned msg, WPARAM wParam, LPARAM lParam);
    LRESULT CALLBACK PrintDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
    BOOL PrintDlg_OnInitDialog(HWND hwndDlg, HWND hwndFocus, LPARAM lParam);
    void PrintDlg_OnCommand(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify);
    void PrintDlg_OnPaint(HWND hwnd);
    void PrintText(HWND hwndParent, char *pszText);
    void PrintToDisplay(HWND hwndParent, char *pszText);
    LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
    DWORD WINAPI BackgroundPrintThread(LPVOID pVoid);
    
    
    ///
    //
    //      WinMain
    //
    // Main entry point of application. This will be a
    // dialog based app, not a normal window, so this
    // routine acts a little differently than "normal".
    //
    int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
        MSG     msg;
        HWND    hWnd;
        WNDCLASS wc;
    	int index;
    
        hInst = hInstance;
       //1.设计一个窗口类
        if (!hPrevInstance)
        {
            memset(&wc, 0, sizeof(wc));
            wc.lpfnWndProc  = MainWndProc;
            wc.hInstance    = hInstance;
            wc.hIcon        = LoadIcon (hInstance, "GenIco");
            wc.hCursor      = LoadCursor(NULL,IDC_ARROW);
            wc.hbrBackground= GetSysColorBrush(COLOR_BACKGROUND);
            wc.lpszMenuName = "PRINTING_MENU";
            wc.lpszClassName= "PrintDlgClass";
            if (!RegisterClass(&wc))
                return FALSE;
        }
    
    //2.创建窗口,并返回创建成功后的窗口句柄
    
        hWnd = CreateWindow(
            "PrintDlgClass",
            "Background Printing",
            WS_OVERLAPPED|WS_CAPTION|WS_MINIMIZEBOX|WS_SYSMENU,
            CW_USEDEFAULT, // At this point we do not want to
            0,             //  show the window until we know
            0,             //  how big the Dialog Box is so
            0,             //  that we can fit the main window
            NULL,          //  around it.
            NULL,
            hInstance,
            NULL);
    
    	    //创建打印对话框
        hDlgMain = CreateDialog(hInst,
                        MAKEINTRESOURCE(IDD_PRINT),
                        hWnd, PrintDlgProc);
    
    
    	//3.显示及刷新窗口
        ShowWindow(hWnd, nCmdShow);
        ShowWindow(hDlgMain, SW_SHOW);
        //4.消息循环
    
    	while (GetMessage(&msg, NULL, 0, 0))
    	{	// Get Next message in queue
    		if(hDlgMain == NULL || !IsDialogMessage(hDlgMain,&msg))
    		{
    			TranslateMessage(&msg); /* Translate virtual key codes */
    			DispatchMessage(&msg);	/* Dispatches message to window */
    		}
    	} // end while
    
    	// Wait for all threads to terminate. The Window will
        // have already disappeared by this point.
    	//等待各个线程结束
    	for (index = 0; index < gNumPrinting; index++)
    	{
    		DWORD status;
    		do 
    		{	// Wait for thread to terminate
    			GetExitCodeThread(gPrintJobs[index], &status);
    			Sleep(10);
    		} while (status == STILL_ACTIVE);
    
    	} // end for
    
    	return (msg.wParam);  /* Returns the value from PostQuitMessage */
    }
    
    
    //主窗口回调函数
    LRESULT CALLBACK MainWndProc(HWND hWnd, unsigned msg, WPARAM wParam, LPARAM lParam)
    {
        switch (msg)
        {
        case WM_CREATE:
            break;
    
        case WM_COMMAND:
    
            switch (wParam)
            {
            case IDM_ABOUT:
                DialogBox(hInst, "AboutBox", hWnd, (DLGPROC)About);
                break;
            case IDM_EXIT:
                PostQuitMessage(0);
                break;
            default:
                return (DefWindowProc(hWnd, msg, wParam, lParam));
            }
    
        case WM_SETFOCUS:
            // ensure that the Dialog Box has the focus
            SetFocus(hDlgMain);
            break;
    
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
    
        default:
            return DefWindowProc(hWnd, msg, wParam, lParam);
    
        }
        return 0;
    }
    
    
    LRESULT CALLBACK PrintDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        switch (uMsg)
        {
        case WM_CLOSE:
            DestroyWindow(hDlg);
            hDlgMain = NULL;
            break;
            
        case WM_DESTROY:
            return TRUE;
            break;
    
        case WM_SHOWBITMAP:
            if (gbmpDisplay)
                DeleteObject(gbmpDisplay);
    
            gDisplayRect = *(RECT*)wParam;
            gbmpDisplay = (HBITMAP) lParam;
            InvalidateRect(hDlgMain, NULL, TRUE);
            break;
    
        HANDLE_MSG(hDlg, WM_INITDIALOG, PrintDlg_OnInitDialog);
        HANDLE_MSG(hDlg, WM_COMMAND, PrintDlg_OnCommand);
        HANDLE_MSG(hDlg, WM_PAINT, PrintDlg_OnPaint);
    
        default:
            return (FALSE);
        }
    
        return 0;
    }
    
    BOOL PrintDlg_OnInitDialog(HWND hwndDlg, HWND hwndFocus, LPARAM lParam)
    {
        RECT rect;
    
        // Size parent to fit this dialog
        GetWindowRect(hwndDlg, &rect); 
        SetWindowPos(GetParent(hwndDlg),NULL,
            0,0,
            rect.right-rect.left,
            rect.bottom-rect.top+GetSystemMetrics(SM_CYMENU)
                +GetSystemMetrics(SM_CYCAPTION),
            SWP_NOMOVE | SWP_NOZORDER);
    
        return TRUE;
    }
    
    void PrintDlg_OnCommand(HWND hDlg, int id,HWND hwndCtl, UINT codeNotify)
    {
        char szText[256];
    
        switch (id)
        {
        case IDC_PRINT:
            GetDlgItemText(hDlg, IDC_EDIT_TEXT, szText, 256);
            PrintText(hDlg, szText);
            break;
    
        case IDC_DISPLAY:
            GetDlgItemText(hDlg, IDC_EDIT_TEXT, szText, 256);
            PrintToDisplay(hDlg, szText);
            break;
    
        case IDCANCEL:
        case IDM_EXIT:
            PostMessage(GetParent(hDlg),WM_DESTROY,
                            (WPARAM)0, (LPARAM)0);
            DestroyWindow(hDlgMain);
            hDlgMain = NULL;
            break;
            
        default:
            break;
        }
    }
    
    void PrintDlg_OnPaint( HWND hwnd )
    {
        PAINTSTRUCT paint;
        HWND hwndCtrl;
    	HDC hdc;
        HDC hDcMem;
        HBITMAP bmpOld;
        RECT rect;
        POINT point;
    
    	if (!gbmpDisplay)
    		return;
    
        hwndCtrl = GetDlgItem(hwnd, IDC_OUTPUT);
    
        hdc = BeginPaint(hwnd, &paint);
    
        GetWindowRect(hwndCtrl, &rect);
        point = *((POINT *)&rect);
        ScreenToClient(hwnd, &point);
    
        hDcMem = CreateCompatibleDC(NULL);
        bmpOld = SelectObject(hDcMem, gbmpDisplay);
    
        // Copy bitmap to screen
        MTVERIFY( BitBlt(hdc, point.x+10, point.y+40,
            gDisplayRect.right-gDisplayRect.left, gDisplayRect.bottom-gDisplayRect.top,
            hDcMem, iHeight, 0, SRCCOPY) );
    
        SelectObject(hDcMem, bmpOld);
        DeleteDC(hDcMem);
    
        EndPaint(hwnd, &paint);
    }
    
    //
    // Asks user which printer to use, then creates
    // background printing thread.
    //
    void PrintText(HWND hwndParent, char *pszText)
    {
        ThreadPrintInfo *pInfo;
        HANDLE hThread;
        DWORD dwThreadId;
        int result;
        DOCINFO docInfo;
    
        PRINTDLG dlgPrint;
    
        // Put up Common Dialog for Printing and get hDC.
        memset(&dlgPrint, 0, sizeof(PRINTDLG));
        dlgPrint.lStructSize = sizeof(PRINTDLG);
        dlgPrint.hwndOwner = hwndParent;
        dlgPrint.Flags = PD_ALLPAGES | PD_USEDEVMODECOPIES
               | PD_NOPAGENUMS | PD_NOSELECTION | PD_RETURNDC;
        dlgPrint.hInstance = hInst;
        if (!PrintDlg(&dlgPrint))
            return;
    
        // Initialize Printer device
        docInfo.cbSize = sizeof(DOCINFO);
        docInfo.lpszDocName = "Background Printing Example";
        docInfo.lpszOutput = NULL;
        docInfo.lpszDatatype = NULL;
        docInfo.fwType = 0;
        result = StartDoc(dlgPrint.hDC, &docInfo);
        result = StartPage(dlgPrint.hDC);
    
        pInfo = HeapAlloc(GetProcessHeap(),
                          HEAP_ZERO_MEMORY,
                          sizeof(ThreadPrintInfo));
        pInfo->hDlg = hwndParent;
        pInfo->hWndParent = hwndParent;
        pInfo->hDc = dlgPrint.hDC;
        pInfo->bPrint = TRUE;
        strcpy(pInfo->szText, pszText);
    
        MTVERIFY( hThread = CreateThread(NULL, 0,
            BackgroundPrintThread, (LPVOID)pInfo,
            0, &dwThreadId ));
    
    	// keep track of all background printing threads
        gPrintJobs[gNumPrinting++] = hThread;
    }
    
    //
    // Shows output on the dialog box.
    //
    void PrintToDisplay(HWND hwndParent, char *pszText)
    {
        ThreadPrintInfo *pInfo;
        DWORD dwThreadId;
        HANDLE hThread;
    
        pInfo = HeapAlloc(GetProcessHeap(),
                          HEAP_ZERO_MEMORY,
                          sizeof(ThreadPrintInfo));
        pInfo->hDlg = hwndParent;
        pInfo->hWndParent = GetDlgItem(hwndParent, IDC_OUTPUT);
    	pInfo->hDc = GetDC(pInfo->hWndParent);
        pInfo->bPrint = FALSE;
        strcpy(pInfo->szText, pszText);
    
        MTVERIFY( hThread = CreateThread(NULL, 0,
                                         BackgroundPrintThread,
                                         (LPVOID)pInfo,
                                         0, &dwThreadId ));
    
    	// keep track of all background printing threads
        gPrintJobs[gNumPrinting++] = hThread;
    }
    
    
    
    //---------------------------------------------------------
    // About Box Handling
    //---------------------------------------------------------
    
    LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message) {
            case WM_COMMAND:
                if (LOWORD(wParam) == IDOK
                    || LOWORD(wParam) == IDCANCEL)
                {
                    EndDialog(hDlg, TRUE);
                    return (TRUE);
                }
                break;
    
            default:
                return (DefWindowProc(hDlg, message, wParam, lParam));
        }
    
        return FALSE;
    }
    
    
    //---------------------------------------------------------
    // Background Printing Code后台线程打印函数
    //---------------------------------------------------------
    
    DWORD WINAPI BackgroundPrintThread(LPVOID pVoid)
    {
        ThreadPrintInfo *pInfo = (ThreadPrintInfo*) pVoid; 
        RECT rect;
        RECT rectMem;
        HDC hDcMem;
        HBITMAP bmpMem;
        HBITMAP bmpOld;
        int x, y;
        int counter = 0;
        int nHeight;
        HFONT hFont;
        HFONT hFontOld;
    
        // Get dimensions of paper into rect
        rect.left = 0;
        rect.top = 0;
        rect.right =  GetDeviceCaps(pInfo->hDc, HORZRES);
        rect.bottom = GetDeviceCaps(pInfo->hDc, VERTRES);
    
        nHeight = -MulDiv(36, GetDeviceCaps(pInfo->hDc, LOGPIXELSY), 72);
    
        // Create Font
        hFont = CreateFont(nHeight, 0, 
            0, 0, FW_DONTCARE, 
            FALSE, FALSE, FALSE, 
            ANSI_CHARSET, 
            OUT_TT_PRECIS, 
            CLIP_DEFAULT_PRECIS,
            PROOF_QUALITY, 
            VARIABLE_PITCH,
            NULL);
        MTASSERT( hFont != 0);
    
        // Draw into memory device context
        hDcMem = CreateCompatibleDC(pInfo->hDc);
        hFontOld = SelectObject(hDcMem, hFont);
        iHeight = DrawText(hDcMem, pInfo->szText, -1,  &rect, DT_LEFT | DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
        rectMem = rect;
        rectMem.left = rect.left + iHeight;
        rectMem.right = rect.right + (iHeight*2);
        bmpMem = CreateCompatibleBitmap(hDcMem,
                                        rectMem.right, rect.bottom);
        bmpOld = SelectObject(hDcMem, bmpMem);
        OffsetRect(&rect, iHeight, 0); 
        DrawText(hDcMem, pInfo->szText, -1,  &rect,
                 DT_LEFT | DT_NOPREFIX | DT_WORDBREAK);
    
        // Italicize bitmap. We use GetPixel and
        // SetPixel because they are horribly inefficient,
        // thereby causing the thread to run for awhile.
        for (y = 0; y < iHeight; y++)
        {   // Italicize line y
            for (x = rectMem.right; x > iHeight; x--)
            {   // Move specified pixel to the right.
                COLORREF color;
                int offset;
                offset = y - iHeight;
                color = GetPixel(hDcMem, x + offset, y);
                if (color != 0)
                    counter++;
                SetPixel(hDcMem, x, y, color);
            } // end for x
        } // end for y
        MTASSERT( counter > 0);
    
        // Copy bitmap of italicized text from memory to device
        if (pInfo->bPrint)
        {
            BitBlt(pInfo->hDc, 50, 50, rectMem.right-rect.left, rectMem.bottom-rect.top,
                hDcMem, iHeight, 0, SRCCOPY);
        }
    
        SelectObject(hDcMem, hFontOld);
        SelectObject(hDcMem, bmpOld);
        DeleteDC(hDcMem);
    
        if (!pInfo->bPrint)
        {
            // We can't just write to the global variable where the
            // bitmap is kept or we might overwrite the work of
            // another thread, thereby "losing" a bitmap
    
            // Also, if we used PostMessage instead of SendMessage, then
            // the rectangle could have been deleted (it's on the stack)
            // by the time the main message loop is reached.
            SendMessage(pInfo->hDlg, WM_SHOWBITMAP, (WPARAM)&rectMem, (LPARAM) bmpMem);
        }
    
        if (pInfo->bPrint)
        {   // Finish printing
            int result;
    
            result = EndPage(pInfo->hDc);
            MTASSERT (result != SP_ERROR);
            result = EndDoc(pInfo->hDc);
            MTASSERT (result != SP_ERROR);
            DeleteDC(pInfo->hDc);
            // If we are printing, we are done with the bitmap.
            DeleteObject(bmpMem);
        } 
        else
        {
            ReleaseDC(pInfo->hWndParent, pInfo->hDc);
        }
    
        // free data structure passed in.
        HeapFree(GetProcessHeap(), 0, pInfo);
    
        return 0;
    }
    


    多线程应该遵循下面原则:
    1.各个线程的数据要分离开来,避免使用全局变量
    2.不要在线程之间共享GDI对象
    3.让主线程处理GUI界面
    4.要等其他线程结束在结束程序







    展开全文
  • 线程 NSThread 多线程 获取当前线程

    万次阅读 2014-02-21 18:55:19
    线程 NSThread 多线程 线程与进程 进程 是一个活动的程序,一个容器 ...一个NSThread对象在程序中控制一个线程,当你有很多任务需要执行,但又不想阻塞主线程时, 多线程将会很有用。运用多线程可以同时执行多个任务。
  • // 如果设置此值,线程执行完毕,会等keepAliveTime时长,如果还没有任务执行,线程池中线程就关闭了 executor.prestartAllCoreThreads(); // 预启动所有核心线程 try { Thread.sleep(10 * 1000); } catch ...
  • 线程执行状态以及通信方式

    万次阅读 2020-01-29 15:38:32
    线程对象创建后,其他线程(比如mian线程)调用了该对象的start方法,该状态线程位于可运行线程池中,等待被线程调度选中,获取cpu的使用权 3运行(running): 可运行状态线程获得了cpu时间片,执行程序代码 4.阻塞...
  • /* 练习: 创建两个线程,和主线程交替运行 原来线程都有自己默认的名称 ...static Thread currentThread():获取当前线程对象 getName():获取线程名称 设置线程名称:setName
  • Java线程的6种状态及切换(透彻讲解)

    万次阅读 多人点赞 2016-12-24 16:57:03
    Java中线程状态分为6种。 1. 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。 2. 运行(RUNNABLE):Java...该状态线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状...
  • Java多线程03_线程状态、优先级、用户线程和守护线程 线程方法: setPriority() 更改线程优先级 static void sleep() 线程休眠 void join() 插队 static void yield() 礼让 void interrupt() 中断...
  • 获取线程池中任务执行数量

    千次阅读 2019-07-04 18:03:25
    通过线程池进行任务处理,有时我们需要知道线程池中任务的执行状态。 通过ThreadPoolExecutor的相关API实时获取线程数量,排队任务数量,执行完成线程数量等信息。 private static ExecutorService es = new ...
  • java指令-jstack查看当前程序线程状态

    千次阅读 2017-02-15 10:21:31
    java指令-jstack查看当前程序线程状态
  • 线程状态和基本操作

    千次阅读 多人点赞 2019-10-03 23:36:42
    在上一篇博客中并发编程的优...文章目录创建线程的四种方式线程状态和生命周期线程状态的基本操作interruptedjoinsleepyield进程和线程线程优先级守护线程和用户线程守护线程详解线程死锁认识线程死锁如何避免线...
  • android 线程状态

    千次阅读 2017-02-22 22:24:08
    · Runnable(可运行):在线程对象上调用start方法后,相应线程便会进入Runnable状态,若被线程调度程序调度,这个线程便会成为当前运行(Running)的线程; · Blocked(被阻塞):若一段代码被线程A”上锁“,...
  • 在C#中如何判断线程当前所处的状态

    万次阅读 多人点赞 2014-11-20 16:53:59
    在C#中,线程对象Thread使用ThreadState属性指示线程状态,它是带Flags特性的枚举类型对象,因此判断线程当前状态必须用bitmask按位运算来达到判断目的,不能直接使用相等来判断。
  • 为了保证系统响应迅速,需要寻找一种方法能够使调取接口能够异步执行,而Java正好提供了类似的方法,在java.util.concurrent中包含了Future相关的类,运用其中的一些类可以进行异步计算,以减少主线程的等待时间。...
  • [超级链接:Java并发学习系列-绪论] 本章主要对Java中线程的状态转换进行学习。 1.前言 ...thread.join():在当前线程中加入指定线程,使得这个指定线程等待当前线程,并在当前线程结束前结束。 t...
  • Java线程状态分析/线程状态转换图

    万次阅读 多人点赞 2018-05-12 10:16:16
    注:以下代码讲解基于JDK1.8.0_144一、线程状态分类 线程一共有六种状态,分别为New、RUNNABLE、BLOCKED、WAITING、TIMED_WAITINGTERMINATED,同一时刻只有一种状态,通过线程的getState方法可以获取线程状态。...
  • 线程池使用FutureTask的时候如果拒绝策略设置为了 DiscardPolicy和DiscardOldestPolicy并且在被拒绝的任务的Future对象上调用无参get方法那么调用线程会一直被阻塞。 问题复现 下面就通过一个简单的例子来复现问题...
  • Thread03之多线程线程状态

    万次阅读 2019-10-16 18:05:22
    ------ 我 QQ:1755497577(备注:博客) ...当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。 在线程的生命周期中,有几种状态呢?在API中 java.lang.Threa...
  • 线程执行流程及各个阶段的状态

    千次阅读 2018-07-30 21:58:55
    线程在一定条件下,状态会发生变化。线程一共有以下几种状态: 1、新建状态(New):新创建了一个线程对象。 2、就绪状态(Runnable):线程...该状态线程位于“可运行线程池”中,变得可运行,只等待获取CPU的使...
  • 在编程工作中,我们经常...接下来我们会映照上图介绍多线程执行过程中经历的五种状态: 1. 新建状态: 新建状态就是我们通过new关键字实例化出一个线程类的对象时的状态。 public class IsAThread extends Thre...
  • 查看jvm中线程状态执行情况

    千次阅读 2019-08-28 14:04:17
    查看java的pid:ps –ef|grep java ...用jstack dump 线程的信息(查看哪个进程,就要用启动那个进程的用户去查询) sudo -u ody /usr/local/java/jdk1.7.0_80/bin/jstack 6396 >6396.dump ...
  • 主要展示Java线程状态,以及状态的转换
  • 线程之间状态和转换

    千次阅读 2016-11-21 15:23:52
    线程创建之后并不是直接开始运行的,而是分了各种状态以便于管理,这样想,cpu就一个,及时你的电脑是4核或者8核,那么也只能同时运行这么多,...就绪:这是的线程已经执行了start()方法,等待获取cpu的运行权限. 运行:这个时候
  • 获取当前正在运行的所有线程

    千次阅读 2018-08-31 14:49:44
    private Thread[] findAllThreads() { ThreadGroup group = Thread.currentThread().getThreadGroup(); ThreadGroup topGroup = group;... /* 遍历线程组树,获取线程组 */ while (group != null) { t...
  • 首先要说的是线程状态,了解了线程状态以及状态切换的过程基本上就了解了多线程线程状态1、新建状态(New):新创建了一个...3、运行状态(Running):就绪状态线程获取了CPU,执行程序代码。 4、阻塞状态(Block
  • Java中停止线程执行的方法

    万次阅读 2015-06-27 15:51:29
    Java中停止线程执行的方法作者:chszs,转载需注明。博客主页:http://blog.csdn.net/chszs一、暂停或停止线程的理论在Java编程中,要暂停或停止当前正在运行的线程,有几种方法。对于把线程转入睡眠Sleep状态,使用...
  • 1.获取线程的名称 参考:https://blog.csdn.net/luyaran/article/details/80595772  public class Main extends Thread {  public static void main(String[] args) {  Main t1 = new Main();  t1.setName(&...
  • 转载自:http://blog.csdn.net/jasonblog/article/details/49909163如果要获取当前线程的调用栈,可以直接使用现有API:[NSThread ...我的理解是应该包含当前线程执行地址,并且从这个地址可以一级一...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 527,931
精华内容 211,172
关键字:

如何获取当前线程的执行状态