Android面试之J2SE基础

来源:互联网 发布:flash cc mac 编辑:程序博客网 时间:2024/05/19 01:06

21. 实现多线程的两种方法

  1. 实现Runnable接口:实际工作中,几乎所有的多线程应用都用实现Runnable这种方式。
    • Runnable适合多个相同程序代码的线程去处理统一资源的情况。把虚拟CPU通程序的代码、数据有效的分离,较好的体现了面向对象的设计思想。
    • 避免由于Java的单继承特性带来的局限性。也就是如果新建的类要继承其他类的话,因为JAVA中不支持多继承,就只能实现java.lang.Runnable接口。
    • 有利用程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。
  2. 继承Thread类:
    • 不能再继承其他类
    • 编写简单,可直接操纵线程,无需使用Thread.currentThread().

22. 线程同步的方法

  1. synchronized关键字和Lock:当使用线程来同时运行多个任务时,可以通过使用锁(互斥)来同步两个任务的行为,从而使得一个任务不会干涉另一个任务的资源。也就是说,如果两个任务在交替着步入某项共享资源,你可以使用互斥来使得任何时刻只有一个任务可以访问这项资源。

    • synchronized:在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态;在资源竞争不是很激烈的情况下,偶尔会有同步的情形下,synchronized是很合适的。原因在于,编译程序通常会尽可能的进行优化synchronize,另外可读性非常好,不管用没用过5.0多线程包的程序员都能理解。
    • ReentrantLock:ReentrantLock 拥有Synchronized相同的并发性和内存语义,此外还多了 锁投票,定时锁等候和中断锁等候。ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。
      • ReentrantLock获取锁定与三种方式:
        • lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁。
        • tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false。
        • tryLock(long timeout,TimeUnit unit), 如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false。
        • lockInterruptibly:如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断。
    • Atomic:和上面的类似,不激烈情况下,性能比synchronized略逊,而激烈的时候,也能维持常态。激烈的时候,Atomic的性能会优于ReentrantLock一倍左右。但是其有一个缺点,就是只能同步一个值,一段代码中只能出现一个Atomic的变量,多于一个同步无效。因为他不能在多个Atomic之间同步。
    • 线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定,如果使用synchronized ,如果A不释放,B将一直等下去,不能被中断。如果使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情。
    • synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中
  2. Object的方法wait()和notify()或者Condition的await()和signal()方法:任务彼此之间协作一起去解决某个问题,在解决这个问题中,由于某些部分必须在其他部分被解决之前解决。

    • wait():使一个线程处于等待状态,并且释放所持有的对象的lock。会在等待外部世界产生变化时将任务挂起,并且只有在notify或notifyAll发生时,这个任务才会被唤醒病区检查所产生的变化。因此,wait()提供了一种在任务之间对活动同步的方式。
    • sleep():使一个正在运行的线程处于睡眠状态,是Thread的一个静态方法,调用此方法需要捕捉InterruptedException异常,没有释放锁。
    • notify():在众多等待同一个锁的任务中只有一个会被唤醒。注意的是在调用此方法时,并不能确切的唤醒某一个等待的线程,而是有JVM确定唤醒哪个线程,而不是按优先级。
    • notifyAll():将唤醒所有正在等待的任务。当notifyAll()因某个特定所而被调用时,只有等待这个锁的任务才会被唤醒,注意不是给所有唤醒线程一个对象的锁,而是让它们竞争。

23. 锁的等级

  1. 方法锁:对象锁(也叫方法锁)。同步静态方法/静态变量互斥体,由于一个class不论被实例化多少次,其中的静态方法和静态变量在内存中都只由一份。所以,一旦一个静态的方法被申明为synchronized。此类所有的实例化对象在调用此方法,共用同一把锁,我们称之为类锁。一旦一个静态变量被作为synchronized block的mutex。进入此同步区域时,都要先获得此静态变量的对象锁。
  2. 对象锁:是针对一个对象的,它只在该对象的某个内存位置声明一个标志位标识该对象是否拥有锁,所以它只会锁住当前的对象。一般一个对象锁是对一个非静态成员变量进行syncronized修饰,或者对一个非静态方法进行syncronized修饰。对于对象锁,不同对象访问同一个被syncronized修饰的方法的时候不会阻塞住。
  3. 类锁:是锁住整个类的,当有多个线程来声明这个类的对象的时候将会被阻塞,直到拥有这个类锁的对象被销毁或者主动释放了类锁。这个时候在被阻塞住的线程被挑选出一个占有该类锁,声明该类的对象。其他线程继续被阻塞住。
  4. 对象锁是用来控制实例方法之间的同步,类锁是用来控制静态方法(或静态变量互斥体)之间的同步。所谓的类锁,不过是Class对象的锁而已。获取类的Class对象有好几种,最简单的就是MyClass.class的方式。

24. 写出生产者消费者模式

  1. wait()和notify()实现:
<code class="hljs cs has-numbering">package com.xqq.生产者与消费者之wait和notify实现;import java.util.LinkedList;import java.util.Queue;<span class="hljs-comment">/** * 用于存放生产数据的缓冲区队列 * @author xqq */</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> FlowQueue<T> {    <span class="hljs-keyword">private</span> Queue<T> queue = <span class="hljs-keyword">new</span> LinkedList<T>();    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> maxSize;    <span class="hljs-keyword">public</span> <span class="hljs-title">FlowQueue</span>(<span class="hljs-keyword">int</span> maxSize) {        <span class="hljs-keyword">this</span>.maxSize = maxSize;    }    <span class="hljs-keyword">public</span> synchronized <span class="hljs-keyword">void</span> <span class="hljs-title">put</span>(T v) throws InterruptedException{        <span class="hljs-keyword">while</span>(queue.size() >= maxSize){            wait();        }        queue.offer(v);        notifyAll();    }    <span class="hljs-keyword">public</span> synchronized T <span class="hljs-title">get</span>() throws InterruptedException{        <span class="hljs-keyword">while</span>(queue.isEmpty()){            wait();        }        T returnVal = queue.poll();        notifyAll();        <span class="hljs-keyword">return</span> returnVal;    }}package com.xqq.生产者与消费者之wait和notify实现;import java.util.concurrent.TimeUnit;<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> Consumer implements Runnable{    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> delay;    <span class="hljs-keyword">private</span> FlowQueue<Item> input;    <span class="hljs-keyword">public</span> <span class="hljs-title">Consumer</span>(<span class="hljs-keyword">int</span> delay, FlowQueue<Item> input) {        <span class="hljs-keyword">this</span>.delay = delay;        <span class="hljs-keyword">this</span>.input = input;    }    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>() {        <span class="hljs-keyword">for</span>(;;){            <span class="hljs-keyword">try</span> {                System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"Consumer "</span> + input.<span class="hljs-keyword">get</span>());                TimeUnit.MILLISECONDS.sleep(delay);            } <span class="hljs-keyword">catch</span> (Exception e) {                <span class="hljs-keyword">return</span>;            }        }    }}package com.xqq.生产者与消费者之wait和notify实现;import java.util.concurrent.TimeUnit;<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> Producer implements Runnable{    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> delay;    <span class="hljs-keyword">private</span> FlowQueue<Item> output;    <span class="hljs-keyword">public</span> <span class="hljs-title">Producer</span>(<span class="hljs-keyword">int</span> delay, FlowQueue<Item> output) {        <span class="hljs-keyword">this</span>.delay = delay;        <span class="hljs-keyword">this</span>.output = output;    }    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>() {        <span class="hljs-keyword">for</span>(;;){            <span class="hljs-keyword">try</span> {                Item product = <span class="hljs-keyword">new</span> Item();                System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"Product "</span> + product);                output.put(product);                TimeUnit.MILLISECONDS.sleep(delay);            } <span class="hljs-keyword">catch</span> (Exception e) {                <span class="hljs-keyword">return</span>;            }        }    }}package com.xqq.生产者与消费者之wait和notify实现;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> ProducerConsumer {    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span>(String[] args) throws InterruptedException {        <span class="hljs-keyword">int</span> producerSleep = <span class="hljs-number">1</span>;        <span class="hljs-keyword">int</span> consumerSleep = <span class="hljs-number">200</span>;        FlowQueue<Item> fq = <span class="hljs-keyword">new</span> FlowQueue<Item>(<span class="hljs-number">10</span>);        ExecutorService exec = Executors.newCachedThreadPool();        exec.execute(<span class="hljs-keyword">new</span> Producer(producerSleep, fq));        exec.execute(<span class="hljs-keyword">new</span> Consumer(consumerSleep, fq));        TimeUnit.SECONDS.sleep(<span class="hljs-number">2</span>);        exec.shutdownNow();    }}运行结果:Product Item <span class="hljs-number">0</span>Consumer Item <span class="hljs-number">0</span>Product Item <span class="hljs-number">1</span>Product Item <span class="hljs-number">2</span>Product Item <span class="hljs-number">3</span>Product Item <span class="hljs-number">4</span>Product Item <span class="hljs-number">5</span>Product Item <span class="hljs-number">6</span>Product Item <span class="hljs-number">7</span>Product Item <span class="hljs-number">8</span>Product Item <span class="hljs-number">9</span>Product Item <span class="hljs-number">10</span>Product Item <span class="hljs-number">11</span>Consumer Item <span class="hljs-number">1</span>Product Item <span class="hljs-number">12</span>Consumer Item <span class="hljs-number">2</span>Product Item <span class="hljs-number">13</span>Consumer Item <span class="hljs-number">3</span>Product Item <span class="hljs-number">14</span>Consumer Item <span class="hljs-number">4</span>Product Item <span class="hljs-number">15</span>Consumer Item <span class="hljs-number">5</span>Product Item <span class="hljs-number">16</span>Consumer Item <span class="hljs-number">6</span>Product Item <span class="hljs-number">17</span>Consumer Item <span class="hljs-number">7</span>Product Item <span class="hljs-number">18</span>Consumer Item <span class="hljs-number">8</span>Product Item <span class="hljs-number">19</span>Consumer Item <span class="hljs-number">9</span>Product Item <span class="hljs-number">20</span></code>


1.BlockingQueue实现:

<code class="hljs java has-numbering"><span class="hljs-keyword">package</span> com.xqq.生产者与消费者BlockingQueue实现;<span class="hljs-keyword">import</span> java.util.concurrent.BlockingQueue;<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Consumer</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Runnable</span> {</span>    <span class="hljs-keyword">private</span> BlockingQueue<Integer> sharedQueue;    <span class="hljs-keyword">public</span> <span class="hljs-title">Consumer</span>(BlockingQueue<Integer> sharedQueue) {        <span class="hljs-keyword">this</span>.sharedQueue = sharedQueue;    }    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>() {        <span class="hljs-keyword">for</span> (;;) {            <span class="hljs-keyword">try</span> {                System.out.println(<span class="hljs-string">"Consumer "</span> + sharedQueue.take());            } <span class="hljs-keyword">catch</span> (Exception e) {                <span class="hljs-keyword">return</span>;            }        }    }}<span class="hljs-keyword">package</span> com.xqq.生产者与消费者BlockingQueue实现;<span class="hljs-keyword">import</span> java.util.concurrent.BlockingQueue;<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Producer</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Runnable</span>{</span>    <span class="hljs-keyword">private</span> BlockingQueue<Integer> sharedQueue;    <span class="hljs-keyword">public</span> <span class="hljs-title">Producer</span>(BlockingQueue<Integer> sharedQueue) {        <span class="hljs-keyword">this</span>.sharedQueue = sharedQueue;    }    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>() {        <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i<<span class="hljs-number">10</span>; i++){            <span class="hljs-keyword">try</span> {                System.out.println(<span class="hljs-string">"Produce "</span> + i);                sharedQueue.put(i);            } <span class="hljs-keyword">catch</span> (Exception e) {                <span class="hljs-keyword">return</span> ;            }        }    }}<span class="hljs-keyword">package</span> com.xqq.生产者与消费者BlockingQueue实现;<span class="hljs-keyword">import</span> java.util.concurrent.BlockingQueue;<span class="hljs-keyword">import</span> java.util.concurrent.ExecutorService;<span class="hljs-keyword">import</span> java.util.concurrent.Executors;<span class="hljs-keyword">import</span> java.util.concurrent.LinkedBlockingQueue;<span class="hljs-keyword">import</span> java.util.concurrent.TimeUnit;<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProducerConsumerPattern</span> {</span>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span>(String[] args) <span class="hljs-keyword">throws</span> InterruptedException {        ExecutorService exec = Executors.newCachedThreadPool();        BlockingQueue<Integer> sharedQueue = <span class="hljs-keyword">new</span> LinkedBlockingQueue<Integer>();        exec.execute(<span class="hljs-keyword">new</span> Producer(sharedQueue));        exec.execute(<span class="hljs-keyword">new</span> Consumer(sharedQueue));        TimeUnit.SECONDS.sleep(<span class="hljs-number">3</span>);        exec.shutdownNow();    }}运行结果:Produce <span class="hljs-number">0</span>Produce <span class="hljs-number">1</span>Produce <span class="hljs-number">2</span>Produce <span class="hljs-number">3</span>Produce <span class="hljs-number">4</span>Produce <span class="hljs-number">5</span>Produce <span class="hljs-number">6</span>Produce <span class="hljs-number">7</span>Produce <span class="hljs-number">8</span>Produce <span class="hljs-number">9</span>Consumer <span class="hljs-number">0</span>Consumer <span class="hljs-number">1</span>Consumer <span class="hljs-number">2</span>Consumer <span class="hljs-number">3</span>Consumer <span class="hljs-number">4</span>Consumer <span class="hljs-number">5</span>Consumer <span class="hljs-number">6</span>Consumer <span class="hljs-number">7</span>Consumer <span class="hljs-number">8</span>Consumer <span class="hljs-number">9</span></code>

25. ThreadPool用法与优势

  1. 优势:
    • 降低资源消耗:通过重复利用以创建的线程降低创建线程和销毁线程的消耗。
    • 提高响应速度:当任务到达时,任务可以不需要等到线程创建就能立即执行。
    • 提高线程的可管理性:线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
  2. 用法:
      -

26. ThreadLocal的设计理念与作用

ThreadLocal不是用来解决对象共享访问问题的,而主要是提供了保持对象的方法和避免参数传递的方便的对象访问方式。

  • 每个线程中都有一个自己的ThreadLocalMap类对象,可以将线程自己的对象保持到其中,各管各的,线程可以正确的访问到自己的对象。
  • 将一个ThreadLocal静态实例作为key,将不同对象的引用保存到不同线程的ThreadLocalMap中,然后在线程执行的各处通过这个静态ThreadLocal实例的get()方法取得自己线程保存的那个对象,避免了将这个对象作为参数传递的麻烦。 ThreadLocal的应用场合,我觉得最适合的是多线程多实例(每个线程对应一个实例)的对象的访问,并且这个对象很多地方都要用到。

27. Concurrent包里的其它东西

28. wait()和sleep()的区别

  1. 这两个方法来自不同的类分别是,sleep来自Thread类,和wait来自Object类
  2. sleep是Thread的静态类方法,谁调用的谁去睡觉,即使在a线程里调用b的sleep方法,实际上还是a去睡觉,要让b线程睡觉要在b的代码中调用sleep。
  3. 锁: 最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
    • sleep不出让系统资源;wait是进入线程等待池等待,出让系统资源,其他线程可以使用锁。一般wait不会加时间限制,因为如果wait线程的运行资源不够,再出来也没用,要等待其他线程调用notify/notifyAll唤醒等待池中的所有线程,才会进入就绪队列等待OS分配系统资源。sleep()可以用时间指定使它自动唤醒过来,如果时间不到只能调用interrupt()强行打断。
    • Thread.sleep(0)的作用是“触发操作系统立刻重新进行一次CPU竞争”。
  4. 使用范围:wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用。

本文转载自:http://blog.csdn.net/chun0801/article/details/51823709


0 0
原创粉丝点击