zoukankan      html  css  js  c++  java
  • 由Android Looper的实现引发的基础补习

    Android的Looper只允许一个线程中有且只有一个Looper,具体实现使用了ThreadLocal来达到这个目的,如果要在新的线程中进行消息传递,则必须调用Looper的静态方法prepare()

    public class Looper {
        // 每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储(TLS)对象
        private static final ThreadLocal sThreadLocal = new ThreadLocal();
        // Looper内的消息队列
        final MessageQueue mQueue;
        // 当前线程
        Thread mThread;
        // 。。。其他属性
    
        // 每个Looper对象中有它的消息队列,和它所属的线程
        private Looper() {
            mQueue = new MessageQueue();
            mRun = true;
            mThread = Thread.currentThread();
        }
    
        // 我们调用该方法会在调用线程的TLS中创建Looper对象
        public static final void prepare() {
            if (sThreadLocal.get() != null) {
                // 试图在有Looper的线程中再次创建Looper将抛出异常
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            sThreadLocal.set(new Looper());
        }
        // 其他方法
    }

    于是在想,类变量如果是static的(比如int,初始为0),在main和子线程中各创建一个实例后打印这个int值,到底是怎么样的呢(大家有时有没有同样的感觉,可能以前真没想到这么多,或者突然之间质疑自己以前以为的结论?)

    class Program
      {
        static void Main(string[] args)
        {
          Entity entity = new Entity();
          entity.Print();
    
          new Thread(t => { Entity e = new Entity(); e.Print(); }).Start();
          new Thread(t => { Entity e = new Entity(); e.Print(); }).Start();
    
          Entity entity2 = new Entity();
          entity2.Print();
    
          Entity entity3 = new Entity();
          entity3.Print();
          Console.Read();
        }
      }
    
      public class Entity
      {
        private static int count = 0;
        public Entity()
        {
          count++;
        }
        public void Print()
        {
          Console.WriteLine(Thread.CurrentThread.ManagedThreadId+ ":" + count);
        }
      }

    输出:

    9:1
    9:2
    9:3
    10:4
    11:5

    如果替换成ThreadLocal又会是怎么样的呢

    class Program
      {
        static void Main(string[] args)
        {
          Entity entity = new Entity();
          entity.Print();
    
          new Thread(t => { Entity e = new Entity(); e.Print(); }).Start();
          new Thread(t => { Entity e = new Entity(); e.Print(); }).Start();
    
          Entity entity2 = new Entity();
          entity2.Print();
    
          Entity entity3 = new Entity();
          entity3.Print();
          Console.Read();
        }
      }
    
      public class Entity
      {
        private static ThreadLocal<int> threadLocal = new ThreadLocal<int>();
        public Entity()
        {
          if (threadLocal.IsValueCreated)
          {
            threadLocal.Value = threadLocal.Value + 1;
          }
          else
          {
            threadLocal.Value = 0;
          }
        }
        public void Print()
        {
          //Console.WriteLine(Thread.CurrentThread.ManagedThreadId+ ":" + count);
          Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + threadLocal.Value);
        }
      }

    输出
    9:0
    9:1
    9:2
    10:0
    11:0

    可见不同线程中的值各有一个副本,同一线程中类似于上例中的结果(纯Static)。

  • 相关阅读:
    bug的生命周期
    性能测试的流程
    通过画因果图来写测试用例的步骤为___、___、___、___及把因果图转换为状态图共五个步骤。&#160;利用因果图生成测试用例的基本步骤是:
    集成测试中自顶向下集成和自底向上集成两个策略的理解,要谈出它们各自的优缺点和主要适应于哪种类型测试;
    Spring中的八大设计模式
    ssh
    window实用快捷键-win篇
    解决Chrome浏览器“崩溃啦”的问题!
    C语言-格式输出
    AIDA64+RemotePanel 组副屏电脑状态监视器 旧手机废物利用 wifi/数据线 adb驱动
  • 原文地址:https://www.cnblogs.com/cqcmdwym/p/3074138.html
Copyright © 2011-2022 走看看