Java Thread 相关知识点
1. start 与 run 的区别
- start 会新创建一个线程,并且执行重新的run方法中的代码
- run 不会新创建一个线程,而在当前线程内执行 run方法内的代码
- start 方法不能连续调用,否则会抛出 IllegalStateException
1 | package com.walterlife.javacore; |
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
16public 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 | synchronized(monitor) |
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
109package 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
58package 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
31package 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
41import 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
35package 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"));
}
}