Android进程与线程基本知识

Activity 生命周期函数执行过程详解 平时开发中接触到Android的启动以及各种生命周期函数,但是其背后的执行过程是怎么样的呢?本文从源码的角度来分析activity的启动以及它的生命周期函数。 关键的类在分析源码之前,先了解下几个关键的类的作用:ActivityManagerService:activity的启动以及生命周期都统一由ActivityManagerService管理,而ActivityManagerService处于 阅读详情

1.Android进程基本知识:

  我们先来了解下Android中的进程基本知识。

 

  当一个程序第一次启动的时候,Android会启动一个LINUX进程和一个主线程。默认的情况下,所有该程序的组件都将在该进程和线程中运行。 同时,Android会为每个应用程序分配一个单独的LINUX用户。Android会尽量保留一个正在运行进程,只在内存资源出现不足时,Android会尝试停止一些进程从而释放足够的资源给其他新的进程使用, 也能保证用户正在访问的当前进程有足够的资源去及时地响应用户的事件。

 

  我们可以将一些组件运行在其他进程中,并且可以为任意的进程添加线程。组件运行在哪个进程中是在manifest文件里设置的,其中<Activity>,<Service>,<receiver>和<provider>都有一个process属性来指定该组件运行在哪个进程之中。我们可以设置这个属性,使得每个组件运行在它们自己的进程中,或是几个组件共同享用一个进程,或是不共同享用。<application>元素也有一个process属性,用来指定所有的组件的默认属性。 

 

  Android中的所有组件都在指定的进程中的主线程中实例化的,对组件的系统调用也是由主线程发出的。每个实例不会建立新的线程。对系统调用进行响应的方法——例如负责执行用户动作的View.onKeyDown()和组件的生命周期函数——都是运行在这个主线程中的。这意味着当系统调用这个组件时,这个组件不能长时间的阻塞主线程。例如进行网络操作时或是更新UI时,如果运行时间较长,就不能直接在主线程中运行,因为这样会阻塞这个进程中其他的组件,我们可以将这样的组件分配到新建的线程中或是其他的线程中运行。

 

  Android会根据进程中运行的组件类别以及组件的状态来判断该进程的重要性,Android会首先停止那些不重要的进程。按照重要性从高到低一共有五个级别:

 

  前台进程

  前台进程是用户当前正在使用的进程。只有一些前台进程可以在任何时候都存在。他们是最后一个被结束的,当内存低到根本连他们都不能运行的时候。一般来说, 在这种情况下,设备会进行内存调度,中止一些前台进程来保持对用户交互的响应。

 

  如果有以下的情形的那么就是前台进程:  

  这个进程运行着一个正在和用户交互的Activity(这个Activity的onResume()方法被调用)。

  这个进程里有绑定到当前正在和用户交互的确Activity的一个service。

  这个进程里有一个service对象,这个service对象正在执行一个它的生命周期的回调函数(onCreate(), onStart(), onDestroy())

  这个进程里有一个正在的onReceive()方法的BroadCastReiver对象。

 

  可见进程

  可见进程不包含前台的组件但是会在屏幕上显示一个可见的进程是的重要程度很高,除非前台进程需要获取它的资源,不然不会被中止。

 

  如果有如下的一种情形就是可见进程: 

  这个进程中含有一个不位于前台的Activity,但是仍然对用户是可见的(这个Activity的onPause()方法被调用),这是很可能发生的,例如,如果前台Activity是一个对话框的话,就会允许在它后面看到前一个Activity。

  这个进程里有一个绑定到一个可见的Activity的Service。

 

  服务进程

  运行着一个通过startService() 方法启动的service,这个service不属于上面提到的2种更高重要性的。service所在的进程虽然对用户不是直接可见的,但是他们执行了用户非常关注的任务(比如播放mp3,从网络下载数据)。只要前台进程和可见进程有足够的内存,系统不会回收他们。

 

  后台进程

  运行着一个对用户不可见的activity(调用过 onStop() 方法).这些进程对用户体验没有直接的影响,可以在服务进程、可见进程、前台进 程需要内存的时候回收。通常,系统中会有很多不可见进程在运行,他们被保存在LRU (least recently used) 列表中,以便内存不足的时候被第一时间回收。如果一个activity正 确的执行了它的生命周期,关闭这个进程对于用户体验没有太大的影响。

 

  空进程

  未运行任何程序组件。运行这些进程的唯一原因是作为一个缓存,缩短下次程序需要重新使用的启动时间。系统经常中止这些进程,这样可以调节程序缓存和系统缓存的平衡。

 

  Android 对进程的重要性评级的时候,选取它最高的级别。例如,如果一个进程含有一个service和一个可视activity,进程将被归入一个可视进程而不是service进程。

 

  另外,当被另外的一个进程依赖的时候,某个进程的级别可能会增高。一个为其他进程服务的进程永远不会比被服务的进程重要级低。因为服务进程比后台activity进程重要级高,因此一个要进行耗时工作的activity最好启动一个service来做这个工作,而不是开启一个子进程――特别是这个操作需要的时间比activity存在的时间还要长的时候。例如,在后台播放音乐,向网上上传摄像头拍到的图片,使用service可以使进程最少获取到“服务进程”级别的重要级,而不用考虑activity目前是什么状态。broadcast receivers做费时的工作的时候,也应该启用一个服务而不是开一个线程。

 

  2. 单线程模型

  线程在代码是使用标准的java Thread对象来建立,那么在Android系统中提供了一系列方便的类来管理线程——Looper用来在一个线程中执行消息循环,Handler用来处理消息,HandlerThread创建带有消息循环的线程。具体可以看下面的详细介绍。

 

  当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。

 

  在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。

 

  2.1 子线程更新UI Android的UI是单线程(Single-threaded)的。

  为了避免拖住GUI,一些较费时的对象应该交给独立的线程去执行。如果幕后的线程来执行UI对象,Android就会发出错误讯息 CalledFromWrongThreadException。以后遇到这样的异常抛出时就要知道怎么回事了!

 

  2.2 Message Queue

  在单线程模型下,为了解决类似的问题,Android设计了一个Message Queue(消息队列), 线程间可以通过该Message Queue并结合Handler和Looper组件进行信息交换。下面将对它们进行分别介绍:

 

  2.2.1. Message Message消息

  理解为线程间交流的信息,处理数据后台线程需要更新UI,则发送Message内含一些数据给UI线程。

 

  2.2.2. Handler Handler处理者

  是Message的主要处理者,负责Message的发送,Message内容的执行处理。后台线程就是通过传进来的Handler对象引用来sendMessage(Message)。而使用Handler,需要implement 该类的 handleMessage(Message) 方法,它是处理这些Message的操作内容,例如Update UI。通常需要子类化Handler来实现handleMessage方法。

 

  2.2.3. Message Queue Message Queue消息队列

  用来存放通过Handler发布的消息,按照先进先出执行。 每个message queue都会有一个对应的Handler。Handler会向message queue通过两种方法发送消息:sendMessage或post。这两种消息都会插在message queue队尾并按先进先出执行。但通过这两种方法发送的消息执行的方式略有不同:通过sendMessage发送的是一个message对象,会被Handler的handleMessage()函数处理;而通过post方法发送的是一个runnable对象,则会自己执行。

 

  2.2.4. Looper Looper是每条线程里的Message Queue的管家。

  Android没有Global的Message Queue,而Android会自动替主线程(UI线程)建立Message Queue,但在子线程里并没有建立Message Queue。所以调用Looper.getMainLooper()得到的主线程的Looper不为NULL,但调用Looper.myLooper()得到当前线程的Looper就有可能为NULL。

 

  对于子线程使用Looper,API Doc提供了正确的使用方法: 

复制代码
package com.test;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;

class LooperThread  extends Thread { 
     public Handler mHandler; 
    
     public  void run() { 
        Looper.prepare();  // 创建本线程的Looper并创建一个MessageQueue
        mHandler =  new Handler() { 
             public  void handleMessage(Message msg) { 

             //  process incoming messages here 
            } 
        }; 
        
        Looper.loop();  // 开始运行Looper,监听Message Queue 
    }     
} 
复制代码

 

  这个Message机制的大概流程:

  1. 在Looper.loop()方法运行开始后,循环地按照接收顺序取出Message Queue里面的非NULL的Message。

 

  2. 一开始Message Queue里面的Message都是NULL的。当Handler.sendMessage(Message)到Message Queue,该函数里面设置了那个Message对象的target属性是当前的Handler对象。随后Looper取出了那个Message,则调用该Message的target指向的Hander的dispatchMessage函数对Message进行处理。
 
  在dispatchMessage方法里,如何处理Message则由用户指定,三个判断,优先级从高到低:
 
  1) Message里面的Callback,一个实现了Runnable接口的对象,其中run函数做处理工作;

  2) Handler里面的mCallback指向的一个实现了Callback接口的对象,由其handleMessage进行处理;

  3) 处理消息Handler对象对应的类继承并实现了其中handleMessage函数,通过这个实现的handleMessage函数处理消息。
 
  由此可见,我们实现的handleMessage方法是优先级最低的!

 

  3. Handler处理完该Message (update UI) 后,Looper则设置该Message为NULL,以便回收!

 

3.Android另外提供了一个工具类:AsyncTask。

它使得UI thread的使用变得异常简单。它使创建需要与用户界面交互的长时间运行的任务变得更简单,不需要借助线程和Handler即可实现。

 

  1) 子类化AsyncTask

 

  2) 实现AsyncTask中定义的下面一个或几个方法

 

  onPreExecute() 开始执行前的准备工作;

 

  doInBackground(Params...) 开始执行后台处理,可以调用publishProgress方法来更新实时的任务进度;

 

  onProgressUpdate(Progress...) 在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。

 

  onPostExecute(Result) 执行完成后的操作,传送结果给UI 线程。

 

  这4个方法都不能手动调用。而且除了doInBackground(Params...)方法,其余3个方法都是被UI线程所调用的,所以要求:

 

  1) AsyncTask的实例必须在UI thread中创建;

 

  2) AsyncTask.execute方法必须在UI thread中调用;

 

  同时要注意:该task只能被执行一次,否则多次调用时将会出现异常。

 

  在使用过程中,发现AsyncTask的构造函数的参数设置需要看明白:

  AsyncTask<Params, Progress, Result> Params对应doInBackground(Params...)的参数类型。

  而new AsyncTask().execute(Params... params),就是传进来的Params数据,你可以execute(data)来传送一个数据,或者execute(data1, data2, data3)这样多个数据。

  Progress对应onProgressUpdate(Progress...)的参数类型;

  Result对应onPostExecute(Result)的参数类型。 当以上的参数类型都不需要指明某个时,则使用Void,注意不是void。不明白的可以参考上面的例子,或者API Doc里面的例子。

 

  下面是关于AsyncTask的使用示例:

复制代码
((Button) findViewById(R.id.load_AsyncTask)).setOnClickListener( new View.OnClickListener(){ 
 
    @Override 
     public  void onClick(View view) { 
        data =  null; 
        data =  new ArrayList<String>(); 
 
        adapter =  null; 
 
         // 显示ProgressDialog放到AsyncTask.onPreExecute()里 
        
// showDialog(PROGRESS_DIALOG); 
         new ProgressTask().execute(data); 
    } 
}); 
 
private  class ProgressTask  extends AsyncTask<ArrayList<String>, Void, Integer> { 
 
/*  该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。 */ 
@Override 
protected  void onPreExecute() { 
     //  先显示ProgressDialog
    showDialog(PROGRESS_DIALOG); 
} 
 
/*  执行那些很耗时的后台计算工作。可以调用publishProgress方法来更新实时的任务进度。  */ 
@Override 
protected Integer doInBackground(ArrayList<String>... datas) { 
    ArrayList<String> data = datas[0]; 
     for ( int i=0; i<8; i++) { 
        data.add("ListItem"); 
    } 
     return STATE_FINISH; 
} 
 
/*  在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用, 
 * 后台的计算结果将通过该方法传递到UI thread. 
 
*/ 
@Override 
protected  void onPostExecute(Integer result) { 
     int state = result.intValue(); 
     switch(state){ 
     case STATE_FINISH: 
        dismissDialog(PROGRESS_DIALOG); 
        Toast.makeText(getApplicationContext(), 
                "加载完成!", 
                Toast.LENGTH_LONG) 
             .show(); 
 
        adapter =  new ArrayAdapter<String>(getApplicationContext(), 
                android.R.layout.simple_list_item_1, 
                data ); 
                 
        setListAdapter(adapter); 
 
         break; 
         
     case STATE_ERROR: 
       dismissDialog(PROGRESS_DIALOG); 
       Toast.makeText(getApplicationContext(), 
               "处理过程发生错误!", 
               Toast.LENGTH_LONG) 
            .show();
 
       adapter =  new ArrayAdapter<String>(getApplicationContext(), 
               android.R.layout.simple_list_item_1, 
               data );
 
          setListAdapter(adapter);
 
           break;
 
    default:
 
   } 
}
复制代码

 

   以上是从网络获取数据,加载到ListView中示例。

 

  4.Android中如何结束进程 

 

  4.1 Android 结束进程,关闭程序的方法 即采用下面这个类

 

  Void android.app.ActivityManager.restartPackage(String packageName)

  public void restartPackage (String packageName)

 

  Since: API Level 3

 

  Have the system perform a force stop of everything associated with the given application package. All processes that share its uid will be killed, all services it has running stopped, all activities removed, etc. In addition, a ACTION_PACKAGE_RESTARTED broadcast will be sent, so that any of its registered alarms can be stopped, notifications removed, etc. You must hold the permission RESTART_PACKAGES to be able to call this method. Parameters packageName The name of the package to be stopped.

 

  使用这个类的具体源代码

final ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);   
am.restartPackage(getPackageName()); 

 

   不要忘记了在配置文件中设置权限:

< uses-permission  android:name ="android.permission.RESTART_PACKAGES" ></ uses-permission > 

 

  结束进程还有

  4.2 android.os.Process.killProcess(pid)

  只能终止本程序的进程,无法终止其它的

 

  public static final void killProcess (int pid)

 

  Kill the process with the given PID. Note that, though this API allows us to request to kill any process based on its PID, the kernel will still impose standard restrictions on which PIDs you are actually able to kill. Typically this means only the process running the caller's packages/application and any additional processes created by that app; packages sharing a common UID will also be able to kill each other's processes.

 

  具体代码如下:

  Process.killProcess(Process.myPid());

Process.killProcess(Process.myPid());

  

  public void finish ()

  Call this when your activity is done and should be closed. The ActivityResult is propagated back to whoever launched you via onActivityResult().

  这是结束当前activity的方法。 要主动的结束一个活动Activity,这里需要注意finish是结束掉一个Activity,而不是一个进程。这个方法最后会调用Activity的生命周期函数onDestroy方法,结束当前的Activity,从任务栈中弹出当前的Activity,激活下一个Activity。当然其他的finish系列方法,我们不在这里做详细讨论。

 

  4.3 System.exit(int code)

  例如: System.exit(0);

  该方法只能用于结束当前进程自身,在程序遇到异常,无法正常执行时,可以 通过这个方法强制退出。 

 

  需要注意的是: android.os.Process.killProcess(pid) 和 System.exit(int code)会导致进程非正常退出,进程退出时不会去执行Activity的onPause、onStop和onDestroy方法,那么进程很有可能错过了保存数据的机会。因此,这两个方法最好使用在出现异常的时候!大家需要注意其使用方法。

 

  4.4 在android2.2版本之后则不能再使用restartPackage()方法,而应该使用killBackgroundProcesses()方法

 

  manager.killBackgroundProcesses(getPackageName());

  使用示例代码如下:

ActivityManager manager = (ActivityManager)getSystemService(ACTIVITY_SERVICE);   
manager.killBackgroundProcesses(getPackageName());

 

//需要在xml中加入权限声明    
< uses-permission  android:name ="android.permission.KILL_BACKGROUND_PROCESSES" />  

 

   另外,在android2.2以后,如果服务在ondestroy里加上了start自己,用kill backgroudprocess通常无法结束自己。

 

  4.5还有一种最新发现的方法,利用反射调用forceStopPackage来结束进程

 
Method forceStopPackage = am.getClass().getDeclaredMethod("forceStopPackage", String. class);  
forceStopPackage.setAccessible( true);  
forceStopPackage.invoke(am, yourpkgname);  


  配置文件中需要添加定义:

android:sharedUserId="android.uid.system"   

 

  另外需要再在配置文件添加权限: 

< uses-permission  android:name ="android.permission.FORCE_STOP_PACKAGES" ></ uses-permission >   

 

  并且采用系统platform签名 因为需要用FORCE_STOP_PACKAGES权限,该权限只赋予系统签名级程序 即可实现强制停止指定程序  

 

  4.6 还有一种方法 利用linux的kill -9命令

 

  4.7 退出到主屏幕(是对当前进程的一种处理) 

  这个方法,也是退出当前进程的一个方法。如果我们在进程中创建了很多的Activity, 但是又不想关闭时去退出不在任务栈顶的Activity ,那么就可以直接使用这个方法了。 

功能:当按下返回键时,就返回到主屏幕,并带有参数 FLAG_ACTIVITY_CLEAR_TOP , 会清理掉当前的活动。 

 

  以下是按下返回键同时不重复时,返回到主屏幕的示例:

复制代码
package  com.test.android; 

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;

/**
 * Andriod按返回键返回到主屏幕示例
 * @Description: Andriod按返回键返回到主屏幕示例

 * @FileName: MyTestProjectActivity.java 

 * @Package com.test.android 

 * @Author Hanyonglu

 * @Date 2012-4-11 上午11:57:31 

 * @Version V1.0
 
*/
public  class MyTestProjectActivity  extends Activity {
     /**  Called when the activity is first created.  */
    @Override
     public  void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
    
    @Override 
     public  boolean onKeyDown( int keyCode, KeyEvent event) { 
         //  event.getRepeatCount():按下返回键,同时没有重复
         if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
            Intent home =  new Intent(Intent.ACTION_MAIN);   
            home.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);   
            home.addCategory(Intent.CATEGORY_HOME);   
            startActivity(home);
        } 
        
         return  super.onKeyDown(keyCode, event);   
    } 
}
复制代码

 

  这种方法其实并没有将进程完全地退出,只是将该程序进入到了后台运行,以便下次更快的启动,所以想要程序进入到后台运行可以考虑采用这种方式。关于这点呢,大家了解就可以了。

 

  以上就是关于Android中进程和线程的基本知识,个人觉得理解这些知识点很重要,虽然它不能让我们在立即能够让我们享受到做出一个产品的成就感,但是可以增强我们的内力,让我们对Android的一些运行机制掌握地更加清楚。

 

Unity多线程单例模式:C#内存模型与线程安全实现详解 在并发编程中,线程安全是确保程序稳定运行的核心概念。C#内存模型定义了多线程环境下内存操作的可见性与顺序性规则,编译器优化和CPU指令重排可能导致未同步的代码出现竞态条件。理解锁机制和内存屏障原理对于构建健壮的多线程应用至关重要,它们不仅提供互斥访问,还保证了线程间的内存一致性。在Unity游戏开发场景中,单例模式作为常用的设计模式,常被用于管理全局状态如音频管理器、配置服务等。当AI计算、资源加载等后台线程与主线程并发访问单例时,若缺乏正确的同步措施,极易引发NullReferenceException等 阅读详情

相关推荐

Unity多线程开发实战:线程锁原理、应用场景与避坑指南

多线程编程是现代软件开发中提升性能的关键技术,它允许多个任务并发执行,从而更高效地利用多核CPU资源。其核心原理在于操作系统对线程的调度与管理,但并发访问共享资源会引发竞态条件,导致数据不一致等线程安全问题。为解决此问题,线程同步技术应运而生,其中线程锁是最基础的同步原语,它通过互斥机制确保临界区代码的原子性执行。在游戏开发与Unity引擎中,多线程技术对于处理后台资源加载、网络通信与复杂计算至关重要,能有效避免主线程阻塞,保障游戏流畅性。然而,Unity引擎API本身并非线程安全,这要求开发者在子线程中协

weixin_33834075的博客 351

Github项目解析(九)-->实现Activity跳转动画的五种方式

文本中我们将讲解activity切换动画相关的知识点,这里的切换动画指的是是activity跳转时的动画效果。这里总结了一下,有五种方式实现activity切换时实现动画效果。下面我将依次介绍一下每种实现activity切换动画效果的实现方式

一片枫叶的专栏 5万+

C#多线程集合选型指南:ConcurrentDictionary与BlockingCollection实战

在多线程编程中,共享集合的并发访问是常见挑战。普通集合如List和Dictionary并非线程安全,多线程读写易导致数据丢失或异常。System.Collections.Concurrent命名空间提供了ConcurrentDictionary、ConcurrentQueue等线程安全集合,通过细粒度锁或无锁算法提升并发性能。合理选型可显著提高吞吐量,适用于缓存、生产者-消费者队列等场景。本文深入解析核心并发集合的内部原理、使用技巧及性能对比,助你避开常见陷阱。

weixin_33912638的博客 276

欢迎使用优快云-markdown编辑器

欢迎使用Markdown编辑器写博客本Markdown编辑器使用StackEdit修改而来,用它写博客,将会带来全新的体验哦: Markdown和扩展Markdown简洁的语法 代码块高亮 图片链接和图片上传 LaTex数学公式 UML序列图和流程图 离线写博客 导入导出Markdown文件 丰富的快捷键 快捷键 加粗 Ctrl + B 斜体 Ctrl + I 引用 Ctrl

kongxingxing的专栏 682

Unity多线程编程:主线程调度器原理、实现与实战应用

在Unity开发中,多线程编程是提升应用性能、避免主线程阻塞的关键技术。其核心原理在于理解Unity引擎的单线程架构限制,即所有与GameObject、Transform及UI组件相关的操作都必须在主线程执行。为解决子线程与主线程间的通信难题,开发者常采用基于队列的任务调度模式,通过线程安全的队列将子线程的计算结果安全地派发回主线程执行。这一技术方案在游戏开发、数字孪生等高性能应用场景中具有重要价值,能有效利用多核CPU处理耗时任务,如资源加载、网络请求和复杂AI计算,从而保障应用的流畅性。本文聚焦于Uni

weixin_34221775的博客 482

C#进阶实战:委托、泛型、异步与多线程在上位机开发中的核心应用

在C#企业级应用开发中,掌握核心编程范式是提升代码质量和解决复杂工程问题的关键。委托与事件机制是实现模块解耦和事件驱动架构的基础原理,它们通过类型安全的函数指针和发布-订阅模型,为系统组件间的松耦合通信提供了标准方案。泛型编程则通过类型参数化实现了代码复用和类型安全,在集合操作和数据处理中能显著提升性能并避免装箱拆箱开销。异步编程模型利用async/await语法,基于任务并行库(TPL)实现非阻塞I/O操作,这对于保持UI响应性和提升系统吞吐量具有重要技术价值。在多线程环境下,线程安全成为保障数据一致性的

weixin_34413802的博客 491

Activity 生命周期回调方法详解

Activity是Android中最最重要的四大组件之一,其生命周期回调方法更是重中之重,只有完全理解完全掌握才能更优雅的使用Activity。这篇文章实例演示各种情景下的Activity生命周期回调方法,相信对你有所帮助O(∩_∩)O谢谢

灰太狼的博客 7139

Unity线程安全单例模式:7种实现方式与性能对比

单例模式是软件设计中常用的创建型模式,它确保一个类只有一个实例,并提供全局访问点。其核心原理是通过私有化构造函数和静态成员来控制实例化过程。在单线程环境下,简单的静态字段或懒加载即可实现,但在多线程并发场景中,若缺乏同步机制,可能导致多个线程同时创建实例,破坏单例的唯一性,引发数据不一致或资源冲突等问题。因此,线程安全单例通过锁(lock)、双重检查锁定(Double-Checked Locking)、Lazy<T>类或利用CLR静态初始化特性等技术,确保实例化过程的原子性与可见性。在Unity游戏开发中,

weixin_30791095的博客 385

Unity多线程编程实战:从并发原理到Job System性能优化

并发与并行是提升软件性能的核心概念。并发通过任务切换提高系统响应能力,而并行利用多核处理器缩短任务执行时间,两者共同构成了现代高性能应用的基础。在游戏开发领域,多线程技术能显著优化CPU密集型计算和I/O操作,从而提升帧率与用户体验。Unity引擎因其独特的线程模型,要求开发者必须遵循严格的线程安全规则,避免直接在主线程外操作UnityEngine对象。通过掌握Task、async/await等现代异步编程工具,以及Unity专为高性能计算设计的C# Job System,开发者可以安全高效地实现并行处理。

weixin_30596165的博客 603

多线程线程安全从原理到实战:C++/C#/Java并发踩坑与解决方案

多线程编程中,数据错乱、程序崩溃、死锁等问题往往源于对线程安全本质的理解不足。从底层原理看,线程安全需要解决可见性、原子性与有序性三大核心问题,而竞态条件则是并发错误的根源。理解这些基础概念后,开发者才能正确运用锁、volatile、原子类及并发容器等工具。在实际工程中,C++单例模式的双重检查锁存在内存序风险,C#的List<T>在并发写入时会因扩容机制产生异常,Java中则需要合理区分synchronized与volatile的边界。与此同时,Meyers Singleton、ConcurrentBag

weixin_33816946的博客 238

手把手教你用C#封装一个MCGS ModbusRTU通讯库(附完整源码)

本文详细介绍了如何使用C#开发一个工业级的MCGS ModbusRTU通讯库,涵盖协议解析、串口通信管理、CRC16校验算法优化等核心功能实现,并提供了与MCGS触摸屏集成的实战示例和完整源码。通过多线程安全读写和自动重试机制设计,确保工业环境下的稳定通讯。

weixin_30243533的博客 335

.NET程序员的专业底线:从代码规范到性能陷阱的实战指南

在.NET开发中,专业性远不止于掌握C#语法或框架API,而是对设计原则、异常处理、内存管理与线程安全等底层机制的系统性理解。DRY、YAGNI、SHY等原则并非抽象教条,而是规避重复逻辑、过度设计和职责错位的关键生存指南;而`async/await`、`Span<T>`、`ConcurrentDictionary`等现代特性,只有结合反射缓存、字符串拼接优化、锁粒度控制等工程实践,才能真正释放性能价值。本文聚焦.NET开发者高频踩坑场景——如裸用`Exception`、误用`ConfigurationMa

a6t2007的博客 467

深入理解C# Lazy<T>:线程安全、内存屏障与6种行为模式

Lazy<T>是.NET中实现延迟初始化的核心泛型类型,其本质是在资源创建开销(CPU/IO/内存)与线程安全保证之间达成精确平衡。它通过内部状态机(Created/Initializing/Initialized/Faulted/Published)和底层内存屏障(非volatile可替代)确保单次、有序、可见的初始化过程。技术价值在于消除手写双重检查锁的指令重排序风险、锁粒度失控及语义污染问题。典型应用场景涵盖EF Core上下文工厂、WPF ViewModel属性、微服务API客户端封装等。本文聚焦L

unixboy 404

.NET Lazy<T>深度解析:延迟初始化原理与高并发实践

Lazy<T> 是 .NET 中实现延迟初始化的核心泛型类型,其本质是将资源创建时机从声明点推迟至首次访问,通过 volatile 可见性、Interlocked 原子操作和 Monitor 同步机制保障多线程安全。它封装了‘是否已初始化’‘谁来初始化’‘失败如何处理’等基础设施逻辑,显著降低手写双检锁(Double-Checked Locking)带来的竞态、重入与异常传播风险。在微服务、高并发订单系统及 Redis/HttpClient 等昂贵资源初始化场景中,Lazy<T> 能确保单例原子加载、避免

unixboy 460

Unity中Protobuf的GC优化实战:对象池与内存管理策略

在Unity游戏开发中,GC(垃圾回收)是影响性能的关键因素之一,尤其当项目涉及大量网络数据传输或复杂状态同步时。GC机制通过自动回收不再使用的内存来管理托管堆,但其回收过程可能导致主线程卡顿,影响游戏流畅度。为减少GC压力,开发者需要从内存分配原理入手,优化短期小对象的创建与销毁频率。对象池技术是解决这一问题的核心方案,它通过复用已有对象而非频繁新建,显著降低托管堆的分配压力。结合序列化技术如Protobuf,可以在网络通信中实现高效数据编码,但需注意其默认用法可能引发额外GC问题。本文聚焦于Unity环

cucanqi9387的博客 612

上位机开发系统指南:从通信协议到工业级应用架构

上位机作为工业自动化系统的核心枢纽,承担着设备通信、数据采集和实时监控等关键任务。其技术原理基于多线程异步处理、工业通信协议解析和界面数据绑定等核心技术,确保系统稳定性和实时性。在工业4.0和智能制造背景下,上位机的技术价值体现在实现设备层与业务层的高效集成,提升生产数据的可视化与决策支持能力。典型应用场景包括PLC控制、视觉检测系统和生产线监控等。本文基于C#、Qt等技术栈,通过Modbus TCP等热词案例,深入解析多线程数据处理和WPF数据绑定等实践要点,帮助开发者构建可靠、可维护的工业级上位机应用体

weixin_34221773的博客 903
上一篇: Android实现程序前后台切换效果
下一篇: 自定义ContentProvide
Jymot
博客等级 码龄14年 6粉丝 15原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值