• Android多线程研究(1)——线程基础及源代码剖析


    从今天起我们来看一下Android中的多线程的知识,Android入门easy,可是要完毕一个完好的产品却不easy,让我们从线程開始一步步深入Android内部。

    一、线程基础回想

    package com.maso.test;
    
    public class TraditionalThread {
    
    	public static void main(String[] args) {
    		/*
    		 * 线程的第一种创建方式
    		 */
    		Thread thread1 = new Thread(){
    			@Override
    			public void run() {
    				try {
    					sleep(1000);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				while(true){
    					System.out.println(Thread.currentThread().getName());
    				}
    			}
    		};
    		thread1.start();
    		
    		/*
    		 *线程的另外一种创建方式 
    		 */
    		Thread thread2 = new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				try {
    					Thread.sleep(1000);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				while (true) {
    					System.out.println(Thread.currentThread().getName());
    				}
    			}
    		});
    		thread2.start();
    		
    		/*
    		 * 线程的调用优先级
    		 */
    		new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				try {
    					Thread.sleep(1000);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				while(true){
    					System.out.println("Runnable");
    				}
    			}
    		}){
    			public void run() {
    				try {
    					sleep(1000);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				while(true){
    					System.out.println("Thread");
    				}
    			};
    		}.start();
    	}
    }
    
    上面代码中是我们都非常熟悉的线程的两种创建方式,假设对这些还感到陌生请先看Java线程基础。


    打开Thread类的源代码能够看到Thread类有8个构造函数。我们先看看上面的两种构造函数的源代码。

        public Thread() {
            init(null, null, "Thread-" + nextThreadNum(), 0);
        }
    在构造的时候直接调用了init方法

        private void init(ThreadGroup g, Runnable target, String name,
                          long stackSize) {
            if (name == null) {
                throw new NullPointerException("name cannot be null");
            }
    
            Thread parent = currentThread();
            SecurityManager security = System.getSecurityManager();
            if (g == null) {
                /* Determine if it's an applet or not */
    
                /* If there is a security manager, ask the security manager
                   what to do. */
                if (security != null) {
                    g = security.getThreadGroup();
                }
    
                /* If the security doesn't have a strong opinion of the matter
                   use the parent thread group. */
                if (g == null) {
                    g = parent.getThreadGroup();
                }
            }
    
            /* checkAccess regardless of whether or not threadgroup is
               explicitly passed in. */
            g.checkAccess();
    
            /*
             * Do we have the required permissions?

    */ if (security != null) { if (isCCLOverridden(getClass())) { security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); } } g.addUnstarted(); this.group = g; this.daemon = parent.isDaemon(); this.priority = parent.getPriority(); this.name = name.toCharArray(); if (security == null || isCCLOverridden(parent.getClass())) this.contextClassLoader = parent.getContextClassLoader(); else this.contextClassLoader = parent.contextClassLoader; this.inheritedAccessControlContext = AccessController.getContext(); this.target = target; setPriority(priority); if (parent.inheritableThreadLocals != null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); /* Stash the specified stack size in case the VM cares */ this.stackSize = stackSize; /* Set thread ID */ tid = nextThreadID(); }

    里面的东西比較多。可是我们能够看到会初始化一个变量Runnable  target;

    以下我们再来看看run方法中是个什么东东?

        @Override
        public void run() {
            if (target != null) {
                target.run();
            }
        }
    原来run方法中会先推断是否初始化了Runnable target变量,假设没有则空实现,假设target不为空则先运行Runnable接口中的run方法。

    有的朋友可能会猜想以下的代码会先调用Runnable接口中的run方法,然后才调用Thread实现类中的run方法。

    		/*
    		 * 线程的调用优先级
    		 */
    		new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				try {
    					Thread.sleep(1000);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				while(true){
    					System.out.println("Runnable");
    				}
    			}
    		}){
    			public void run() {
    				try {
    					sleep(1000);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				while(true){
    					System.out.println("Thread");
    				}
    			};
    		}.start();
    事实上事实并不是如此。由于上面代码中是一个匿名内部类,实际上是一种从Thread的继承和实现,所以以下的run方法覆盖了Thread中的run方法。所以Runnable中的run方法根本不会运行。

    以下再看看Runnable接口的源代码

    public
    interface Runnable {
        /**
         * When an object implementing interface <code>Runnable</code> is used
         * to create a thread, starting the thread causes the object's
         * <code>run</code> method to be called in that separately executing
         * thread.
         * <p>
         * The general contract of the method <code>run</code> is that it may
         * take any action whatsoever.
         *
         * @see     java.lang.Thread#run()
         */
        public abstract void run();
    }
    
    发现Runnable接口仅仅有一个抽象的run方法。

    为什么要搞一个Runnable接口来实现多线程呢?从Thread继承不是更方便吗?Runnable接口有例如以下优势。所以我们经常会选择实现Runnable接口:

    1、适合多个程序代码的线程去处理同一个资源。

    public class ThreadTest1 extends Thread {
    	private int count = 5;
    	 
        public void run() {
            for (int i = 0; i < 7; i++) {
                if (count > 0) {
                    System.out.println("count= " + count--);
                }
            }
        }
     
        public static void main(String[] args) {
        	//这样实际上是创建了三个互不影响的线程实例
            ThreadTest1 t1 = new ThreadTest1();
            ThreadTest1 t2 = new ThreadTest1();
            ThreadTest1 t3 = new ThreadTest1();
            t1.start();
            t2.start();
            t3.start();
        }
    }
    public class ThreadTest1{
         
        public static void main(String [] args) {
            MyThread my = new MyThread();
            //开启了三个线程。可是操作的是同一个run方法
            new Thread(my, "1号窗体").start();
            new Thread(my, "2号窗体").start();
            new Thread(my, "3号窗体").start();
        } 
    }
    
    class MyThread implements Runnable{
    	 
        private int ticket = 5;  //5张票
     
        public void run() {
            for (int i=0; i<=20; i++) {
                if (this.ticket > 0) {
                    System.out.println(Thread.currentThread().getName()+ "正在卖票"+this.ticket--);
                }
            }
        }
    }

    2、避免Java特性中的单根继承的限制。

    3、能够保持代码和数据的分离(创建线程数和数据无关)。

    4、更能体现Java面向对象的设计特点。




  • 相关阅读:
    Java中的多线程
    谈谈Java中的类型识别RTTI
    Java中的几个重要的数据类型
    编译和运行Java程序
    说说Java中的接口
    说说Java的反射
    谈谈Java中的新的IO特性
    谈谈Java中的内部类
    谈谈Java中的类
    老妈也加入偷菜行列了
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/6862413.html
Copyright © 2020-2023  润新知