zoukankan      html  css  js  c++  java
  • Android多线程研究(1)——线程基础及源码剖析

    从今天起我们来看一下Android中的多线程的知识,Android入门容易,但是要完成一个完善的产品却不容易,让我们从线程开始一步步深入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面向对象的设计特点。




  • 相关阅读:
    Oracle常用命令大全(很有用,做笔记)
    表格驱动编程在代码中的应用
    mac 利用svn下载远程代码出现Agreeing to the Xcode/iOS license requires admin privileges, please re-run as root via sudo.
    FAILURE: Build failed with an exception.
    There is an internal error in the React performance measurement code.Did not expect componentDidMount timer to start while render timer is still in progress for another instance
    react native TypeError network request failed
    Android向系统相册中插入图片,相册中会出现两张 一样的图片(只是图片大小不一致)
    react-native Unrecognized font family ‘Lonicons’;
    react-native SyntaxError xxxxx/xx.js:Unexpected token (23:24)
    Application MyTest has not been registered. This is either due to a require() error during initialization or failure to call AppRegistry.registerComponent.
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6468951.html
Copyright © 2011-2022 走看看