1. start 与 run 的区别

  • start 会新创建一个线程,并且执行重新的run方法中的代码
  • run 不会新创建一个线程,而在当前线程内执行 run方法内的代码
  • start 方法不能连续调用,否则会抛出 IllegalStateException
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.walterlife.javacore;

import java.lang.Thread;

public class StartVsRunCall {
public static void main( String[] args ) {
Thread startThread = new Thread(new Task("start"), "startThread");
Thread runThread = new Thread(new Task("run"), "runThread");

startThread.start();
runThread.run();
}

private static class Task implements Runnable {
private String caller;

public Task(String caller) {
this.caller = caller;
}

public void run() {
System.out.println("caller: " + this.caller + " and code exectue in thread " + Thread.currentThread().getName());
}
}
}

// Output:
caller: run and code exectue in thread main
caller: start and code exectue in thread startThread

2. extends Thread 和 implements Runnable 有什么区别,哪一个更好

  • extends Thread 需要 自己实现 构造函数,并且构造函数要调父类的构造函数(super(“threadnmae”))和 实现run方法
  • implements Runnable 只需要实现 run 方法即可
  • 因为java不支持多继承,所以使用 implements Runnable 会更好,这样你设计的类还可以继承其他类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class DemoRunnable implements Runnable {
    public void run() {
    //Code
    }
    }
    //with a "new Thread(demoRunnable).start()" call

    public class DemoThread extends Thread {
    public DemoThread() {
    super("DemoThread");
    }
    public void run() {
    //Code
    }
    }
    //with a "demoThread.start()" call

3. Callable 和 Runnable 有什么区别

  • Callable 是在 Runnable 之后添加的,在Java5.0增加的
  • Runnable使用run 方法 而 Callable 使用 call 方法中的方法
  • Runnable 没有返回参数,而Callable 有返回参数,参数类型根据创建实例的泛型参数
  • Runnable 不能抛出 checked exception, 而 Callable可以

4. wait 和 sleep 的区别

  • wait 方法是使用对象调用的[每个Object都有,是成员函数],而 sleep 是 使用 class[Thread] 调用的[是静态函数]
  • wait 方法必须在 synchronized 代码块中调用,不然会抛出 IllegalMonitorStateException异常。sleep 调用没有任何限制
  • 在 synchronized 方法块中调用wait 方法时会释放 locked Object 资源,而sleep 不会
  • wait 需要在 循环中调用,即在条件变量为真时,wait,等到条件变量为假时,从新回到 running 状态, 而 sleep 没有类似的功能,并且最好不要在循环中call sleep
1
2
3
4
synchronized(monitor)
while(condition == true){ monitor.wait()) //releases monitor lock

Thread.sleep(100); //puts current thread on Sleep

5. 使用多线程解决消费者生产者问题

  • 使用非Blocking数据结构实现需要自己实现数据间的同步访问[使用wait, notifyAll, notify, synchronized 实现同步]

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    package com.walterlife.javacore;

    import java.util.Vector;
    import java.util.logging.Level;
    import java.util.logging.Logger;

    public class ProducerConsumerSolution {
    public static void main( String[] args ) {
    Vector<Integer> sharedProduct = new Vector<Integer>();
    int size = 4;

    Thread producer = new Thread(new Producer(sharedProduct, size), "producer");
    Thread consumer = new Thread(new Consumer(sharedProduct, size), "consumer");

    producer.start();
    consumer.start();
    }
    }

    class Producer implements Runnable {

    private final Vector<Integer> sharedProduct;
    private final int SIZE;
    private static int PRODUCTOR_NUM = 7;

    public Producer(Vector sharedProduct, int size) {
    this.sharedProduct = sharedProduct;
    this.SIZE = size;
    }

    public void run() {
    try {
    for(int productor = 0; productor < PRODUCTOR_NUM; productor++) {
    producer(productor);
    }
    } catch(InterruptedException ex) {
    Logger.getLogger(Producer.class.getName()).log(Level.SEVERE, null, ex);
    }
    }

    private void producer(int productor) throws InterruptedException {
    // productor too much, wait
    while(sharedProduct.size() == SIZE) {
    synchronized (sharedProduct) {
    System.out.println("Queue is full " + Thread.currentThread().getName()
    + " is waiting , size: " + sharedProduct.size());
    sharedProduct.wait();
    }
    }

    // producer productor
    synchronized (sharedProduct) {
    sharedProduct.add(productor);
    sharedProduct.notifyAll();
    }
    }
    }

    class Consumer implements Runnable {
    private final Vector<Integer> sharedProduct;
    private final int SIZE;

    public Consumer(Vector sharedProduct, int size) {
    this.sharedProduct = sharedProduct;
    this.SIZE = size;
    }

    public void run() {
    while (true) {
    try {
    System.out.println("Consumed: " + consume());
    Thread.sleep(50);
    } catch (InterruptedException ex) {
    Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex);
    }
    }
    }

    private Integer consume() throws InterruptedException {
    // wait if queue is empty
    while (sharedProduct.isEmpty()) {
    synchronized (sharedProduct) {
    System.out.println("Queue is empty " + Thread.currentThread().getName()
    + " is waiting , size: " + sharedProduct.size());

    sharedProduct.wait();
    }
    }

    // Otherwise consume element and notify waiting producer
    synchronized (sharedProduct) {
    sharedProduct.notifyAll();
    return (Integer) sharedProduct.remove(0);
    }
    }
    }

    // output
    Queue is full producer is waiting , size: 4
    Consumed: 0
    Queue is full producer is waiting , size: 4
    Consumed: 1
    Queue is full producer is waiting , size: 4
    Consumed: 2
    Consumed: 3
    Consumed: 4
    Consumed: 5
    Consumed: 6
    Queue is empty consumer is waiting , size: 0
  • 使用Blocking数据结实现生产者和消费者功能

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    package com.walterlife.javacore;

    import java.util.Vector;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.LinkedBlockingQueue;

    public class ProducerConsumerSolutionV2 {
    public static void main( String[] args ) {
    BlockingQueue<Integer> sharedProduct = new LinkedBlockingQueue<Integer>();

    Thread producer = new Thread(new ProducerV2(sharedProduct), "producer");
    Thread consumer = new Thread(new ConsumerV2(sharedProduct), "consumer");

    producer.start();
    consumer.start();
    }
    }

    class ProducerV2 implements Runnable {

    private final BlockingQueue<Integer> sharedProduct;
    private static int PRODUCTOR_NUM = 7;

    public ProducerV2(BlockingQueue<Integer> sharedProduct) {
    this.sharedProduct = sharedProduct;
    }

    public void run() {
    try {
    for(int productor = 0; productor < PRODUCTOR_NUM; productor++) {
    System.out.println("Produced: " + productor);
    sharedProduct.put(productor);
    }
    } catch(InterruptedException ex) {
    Logger.getLogger(Producer.class.getName()).log(Level.SEVERE, null, ex);
    }
    }
    }

    class ConsumerV2 implements Runnable {
    private final BlockingQueue<Integer> sharedProduct;

    public ConsumerV2(BlockingQueue<Integer> sharedProduct) {
    this.sharedProduct = sharedProduct;
    }

    public void run() {
    while (true) {
    try {
    System.out.println("Consumed: " + sharedProduct.take());
    } catch (InterruptedException ex) {
    Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex);
    }
    }
    }
    }

6. 如何在线程运行的过程中退出

  • 使用一个变量来控制退出
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    package com.walterlife.javacore;

    import java.util.logging.Logger;
    import java.lang.Thread;
    import java.util.logging.Level;

    public class StopThread {
    public static void main (String [] args) {

    }
    }

    class Runner implements Runnable {
    boolean exit = false;

    // 控制 线程退出
    public void exit(boolean exit) {
    this.exit = exit;
    }

    public void run() {
    while (!exit) {
    System.out.print("Thread is running\n");
    try {
    Thread.sleep(20);
    } catch(InterruptedException ex) {
    Logger.getLogger(Runner.class.getName()).log(Level.SEVERE, null, ex);
    }
    }
    }
    }

7. 现有线程 T1, T2, T3, 如何保证3个线程按照顺序执行[T1->T2->T3]

  • 使用 Thread 的join 成员方法来实现
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    import java.util.logging.Level;
    import java.util.logging.Logger;

    public class JoinTest {
    public static void main (String [] args) {
    Thread ta = new Thread(new ThreadA(), "ThreadA");
    Thread tb = new Thread(new ThreadB(), "ThreadB");
    Thread tc = new Thread(new ThreadC(), "ThreadC");
    try {
    ta.start();
    // join 方法 使得 调用的线程必须先执行完,再接着执行下面的代码
    ta.join();
    tb.start();
    tb.join();
    tc.start();
    tc.join();
    System.out.printf("Thrad name: %s\n", Thread.currentThread().getName());
    } catch(InterruptedException ex) {
    Logger.getLogger(JoinTest.class.getName()).log(Level.SEVERE, null, ex);
    }
    }
    }

    class ThreadA implements Runnable {

    public void run() {
    System.out.printf("Thread name: %s\n", Thread.currentThread().getName());
    }
    }

    class ThreadB implements Runnable {
    public void run() {
    System.out.printf("Thread name: %s\n", Thread.currentThread().getName());
    }
    }

    class ThreadC implements Runnable {
    public void run() {
    System.out.printf("Thread name: %s\n", Thread.currentThread().getName());
    }
    }

8. 为什么 wait, notify, notifyAll 方法必须在 synchronized 代码块内执行

  • 首先之所以会调用这些函数,是因为 竞态条件[race condition]发生变化了
  • 而在多线程中如果要检查 竞态条件的状态,必须要获得这个竞态条件的锁
  • synchronized 代码块保证了只有一个线程可以获取竞态条件的锁,并读取值或改变

9. 怎样在线程收到异常时重新启动线程

  • 设置 UncaughtExceptionHandler
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    package com.walterlife.javacore;

    import java.lang.Thread.UncaughtExceptionHandler;

    public class ExceptionHandler {
    public static void main (String [] args) {
    Thread task = new Thread(new Task(), "task_one");
    task.start();
    String a;
    }
    }

    class SelfExceptionHandler implements UncaughtExceptionHandler {
    public void uncaughtException(Thread t, Throwable e) {
    System.out.printf("An exception has been captured\n");
    System.out.printf("Thread: %s\n", t.getId());
    System.out.printf("Exception: %s: %s\n", e.getClass().getName(), e.getMessage());
    System.out.printf("Stack Trace: \n");
    e.printStackTrace(System.out);
    System.out.printf("Thread status: %s\n", t.getState());
    new Thread(new Task(), "task_one").start();
    }
    }

    class Task implements Runnable {
    public void run() {
    Thread.currentThread().setUncaughtExceptionHandler(new SelfExceptionHandler());
    System.out.println(Integer.parseInt("123"));
    System.out.println(Integer.parseInt("123"));
    System.out.println(Integer.parseInt("123"));
    System.out.println(Integer.parseInt("xyz"));
    System.out.println(Integer.parseInt("123"));
    System.out.println(Integer.parseInt("123"));
    }
    }

留言

Jul 21 2015