Java 线程相关测试

基本线程

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
package threadtest;

/**
* 基本线程
* @author zhangqingli
*
*/
public class BaseThread01 {
public static void main(String[] args) {
for (int i = 1; i < 10; i++) {
Calculator01 c = new Calculator01(i);
new Thread(c).start();
}
}
}

class Calculator01 implements Runnable {
private int number;

public Calculator01(int number) {
this.number = number;
}

@Override
public void run() {
for (int i = 1; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ": " + number + ": " + i+"*"+number+"="+i*number);
}
}
}


//测试结果
Thread-0: 1: 1*1=1
Thread-4: 5: 1*5=5
Thread-5: 6: 1*6=6
Thread-3: 4: 1*4=4
Thread-6: 7: 1*7=7
Thread-6: 7: 2*7=14
...
...
Thread-8: 9: 9*9=81
...
Thread-1: 2: 8*2=16
Thread-0: 1: 9*1=9
Thread-1: 2: 9*2=18


获取和设置线程信息

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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package threadtest;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.Thread.State;

/**
* 获取和设置线程信息
* ID: 每个线程的独特标识。
* Name: 线程的名称。
* Priority: 线程对象的优先级。优先级别在1-10之间,1是最低级,10是最高级。不建议改变它们的优先级,但是你想的话也是可以的。
* Status: 线程的状态。在Java中,线程只能有这6种中的一种状态: new, runnable, blocked, waiting, time waiting, terminated.
*/
public class ThreadInfo02 {

public static void main(String[] args) throws IOException {
//
Thread[] threads = new Thread[10];
Thread.State status[] = new Thread.State[10];
//
for (int i=0; i<10; i++){
threads[i]=new Thread(new Calculator02(i));
if ((i%2)==0){
threads[i].setPriority(Thread.MAX_PRIORITY);
} else {
threads[i].setPriority(Thread.MIN_PRIORITY);
}
threads[i].setName("Thread "+i);
}
//
PrintWriter pw = new PrintWriter(new FileWriter("/Users/zhangqingli/Desktop/log.txt"));
for (int i=0; i<10; i++){
pw.println("Main : Status of Thread "+i+" : " +threads[i].getState());
pw.flush();
status[i]=threads[i].getState();
}
//
for (int i = 0; i < 10; i++) {
threads[i].start();
}

//
boolean finish=false;
while (!finish) {
for (int i=0; i<10; i++){
if (threads[i].getState()!=status[i]) {
writeThreadInfo(pw, threads[i], status[i]);
status[i]=threads[i].getState();
}
}
//
finish=true;
for (int i=0; i<10; i++){
finish=finish && (threads[i].getState()==State.TERMINATED);
}
}
}

private static void writeThreadInfo(PrintWriter pw, Thread thread, Thread.State state) {
pw.printf("Main : Id %d - %s\n",thread.getId(),thread.getName());
pw.printf("Main : Priority: %d\n",thread.getPriority());
pw.printf("Main : Old State: %s\n",state);
pw.printf("Main : New State: %s\n",thread.getState());
pw.printf("Main : ************************************\n");
pw.flush();
}
}

class Calculator02 implements Runnable {
private int number;

public Calculator02(int number) {
this.number=number;
}

@Override
public void run() {
for (int i=1; i<=10; i++){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("%s: %d * %d = %d\n", Thread.currentThread().getName(), number, i, i*number);
}
}
}

//执行结果
Thread 1: 1 * 1 = 1
Thread 0: 0 * 1 = 0
Thread 3: 3 * 1 = 3
Thread 2: 2 * 1 = 2
Thread 4: 4 * 1 = 4
Thread 6: 6 * 1 = 6
Thread 7: 7 * 1 = 7
Thread 9: 9 * 1 = 9
Thread 5: 5 * 1 = 5
Thread 8: 8 * 1 = 8
...
Thread 4: 4 * 9 = 36
Thread 9: 9 * 9 = 81
Thread 3: 3 * 9 = 27
...


log.txt
Main : Status of Thread 0 : NEW
Main : Status of Thread 1 : NEW
Main : Status of Thread 2 : NEW
Main : Status of Thread 3 : NEW
Main : Status of Thread 4 : NEW
Main : Status of Thread 5 : NEW
Main : Status of Thread 6 : NEW
Main : Status of Thread 7 : NEW
Main : Status of Thread 8 : NEW
Main : Status of Thread 9 : NEW
Main : Id 8 - Thread 0
Main : Priority: 10
Main : Old State: NEW
Main : New State: TIMED_WAITING
Main : ************************************
Main : Id 9 - Thread 1
Main : Priority: 1
Main : Old State: NEW
Main : New State: TIMED_WAITING
Main : ************************************
...
Main : ************************************
Main : Id 15 - Thread 7
Main : Priority: 1
Main : Old State: TIMED_WAITING
Main : New State: RUNNABLE
Main : ************************************
Main : Id 16 - Thread 8
Main : Priority: 10
Main : Old State: RUNNABLE
Main : New State: TIMED_WAITING
Main : ************************************
Main : Id 9 - Thread 1
Main : Priority: 1
Main : Old State: BLOCKED
Main : New State: TIMED_WAITING
Main : ************************************
...


线程的中断

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
package threadtest;
/**
* 线程的中断
* 1. java中提供 thread.interrupt() 和 thread.isInterrupted() 来控制线程的中断,不过可能会出现难以预料的结果,一般不用这种方法
* 2. 线程的中断我们一般自己写程序判断和控制
*/
public class ThreadInterrupt03 {

public static void main(String[] args) {
PrimeGenerator03 pg = new PrimeGenerator03();
Thread t = new Thread(pg);
t.start();

//等待5秒,然后中断PrimeGenerator线程
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
pg.interrupted = true;
}
}

class PrimeGenerator03 implements Runnable {
volatile boolean interrupted = false;

@Override
public void run() {
long num = 1L;
while (true) {
if (isPrime(num)) {
System.out.printf("Num %d is Prime\n", num);
}

if (this.interrupted) {
System.out.printf("The Prime Generator has been Interrupted\n");
return;
}
num++;

try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private boolean isPrime(long num) { //判断一个数是否是质数
if (num < 2) {
return true;
}
for (int i = 2; i < num; i++) {
if (num%i==0) {
return false;
}
}
return true;
}

}

//执行结果
Num 1 is Prime
Num 2 is Prime
Num 3 is Prime
Num 5 is Prime
Num 7 is Prime
Num 11 is Prime
The Prime Generator has been Interrupted


线程的睡眠与恢复

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
package threadtest;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
* 线程的睡眠与恢复
* @author zhangqingli
*
*/
public class ThreadSleep04 {
public static void main(String[] args) {
new Thread(new FileClock04()).start();
}
}

class FileClock04 implements Runnable {

@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(new Date());
try {
TimeUnit.SECONDS.sleep(1); //1s钟睡一次 等价于Thread.sleep
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

// 执行结果
Tue Mar 21 12:56:38 CST 2017
Tue Mar 21 12:56:39 CST 2017
Tue Mar 21 12:56:40 CST 2017
Tue Mar 21 12:56:41 CST 2017
Tue Mar 21 12:56:42 CST 2017
Tue Mar 21 12:56:43 CST 2017
Tue Mar 21 12:56:44 CST 2017
Tue Mar 21 12:56:45 CST 2017
Tue Mar 21 12:56:46 CST 2017
Tue Mar 21 12:56:47 CST 2017


线程的插入

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
package threadtest;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
* 线程的插入
* thread.join(): 在当前线程中调用该方法时,当前线程会被暂停,直到调用join方法的线程执行完毕!
*
*/
public class ThreadJoin05 {
//
public static void main(String[] args) {
Thread t1 = new Thread(new DataSourceLoader05());
Thread t2 = new Thread(new NetworkConnectionsLoader());
t1.start();
t2.start();

for (int i = 0; i < 10; i++) {
System.out.println("["+ i +"] " + Thread.currentThread().getName());
if (i==5) {
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

class DataSourceLoader05 implements Runnable {

@Override
public void run() {
System.out.println("["+ new Date() +"] datasource loading...");
try {
TimeUnit.SECONDS.sleep(10); //资源加载10s
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("["+ new Date() +"] datasource loading has finished!");
}
}


class NetworkConnectionsLoader implements Runnable {
@Override
public void run() {
System.out.println("["+ new Date() +"] networkConnections loading...");
try {
TimeUnit.SECONDS.sleep(15); //资源加载15s
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("["+ new Date() +"] networkConnections loading has finished!");
}
}


// 执行结果
[0] main
[Tue Mar 21 12:58:04 CST 2017] networkConnections loading...
[Tue Mar 21 12:58:04 CST 2017] datasource loading...
[1] main
[2] main
[3] main
[4] main
[5] main
[Tue Mar 21 12:58:14 CST 2017] datasource loading has finished!
[Tue Mar 21 12:58:19 CST 2017] networkConnections loading has finished!
[6] main
[7] main
[8] main
[9] main


守护线程的创建和运行

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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package threadtest;
import java.util.ArrayDeque;
import java.util.Date;
import java.util.Deque;
import java.util.concurrent.TimeUnit;
/**
* 守护线程的创建和运行
* Java有一种特别的线程叫做守护线程。这种线程的优先级非常低,通常在程序里没有其他线程运行时才会执行它。
* 当进程中不存在非守护线程了,则守护线程自动销毁。典型的守护线程就是垃圾回收线程,当进程中没有非守护
* 线程了,则垃圾回收线程也就没有存在的必要了,自动销毁。用个比较通俗的比喻来解释一下守护线程,就是:
* 任何一个守护线程都是整个JVM非守护线程的“保姆”。
*
* 根据这些特点,守护线程通常用于在同一程序里给普通线程(也叫使用者线程)提供服务。
* 它们通常无限循环的等待服务请求或执行线程任务。它们不能做重要的任务,因为我们不
* 知道什么时候会被分配到CPU时间片,并且只要没有其他线程在运行,它们可能随时被终止。
* JAVA中最典型的这种类型代表就是垃圾回收器。
*
* 在这个测试中, 我们将学习如何创建一个守护线程,开发一个用2个线程的例子;
* 我们的使用线程会写事件到queue, 守护线程会清除queue里10秒前创建的事件。
*/
public class ThreadDaemon06 {
public static void main(String[] args) {
//工作线程向双队列中写事件
Deque<Event> deque = new ArrayDeque<Event>();
for (int i = 0; i < 3; i++) {
new Thread(new WriterTask(deque)).start();
}
//守护线程清除10s之前的时间
CleanerTask cleanerTask = new CleanerTask(deque);
cleanerTask.start();
}
}


class Event {
Date date;
String event;

public Event(Date date, String event) {
this.date = date;
this.event = event;
}
}

class WriterTask implements Runnable {
private Deque<Event> deque; //双向队列,可实现栈的数据结构

public WriterTask(Deque<Event> deque) {
this.deque = deque;
}

@Override
public void run() {
for (int i = 0; i < 100; i++) {
Event event = new Event(new Date(), String.format("The thread %s has generated an event", Thread.currentThread().getId()));
deque.addFirst(event);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

class CleanerTask extends Thread {
private Deque<Event> deque;

public CleanerTask(Deque<Event> deque) {
this.deque = deque;
//设置为守护线程
//只能在start()方法之前可以调用setDaemon()方法。因为一旦线程运行了,就不能修改守护状态。
super.setDaemon(true);
}

@Override
public void run() {
while (true) {
Date date = new Date();
clean(date);
}
}

//它获取最后的事件,如果它在10秒前被创建,就删除它并查看下一个事件。
//如果一个事件被删除,它会写一个事件信息和queue的新的大小,为了让你看到变化过程
private void clean(Date date) {
if (deque.size()==0) {
return;
}
long time = 0;
boolean deleteFlag = false;

do {
Event event = deque.getLast();
time = date.getTime() - event.date.getTime();
if (time > 10000) {
System.out.printf("Cleaner: %s\n", event.event);
deque.removeLast();
deleteFlag = true;
}
} while (time > 10000);

if (deleteFlag) {
System.out.printf("Cleaner: Size of the queue: %d\n", deque.size());
}
}
}


// 运行结果
...
Cleaner: Size of the queue: 19
Cleaner: The thread 10 has generated an event
Cleaner: The thread 8 has generated an event
Cleaner: The thread 9 has generated an event
Cleaner: Size of the queue: 19
Cleaner: The thread 9 has generated an event
Cleaner: The thread 8 has generated an event
Cleaner: Size of the queue: 18
Cleaner: The thread 8 has generated an event
Cleaner: The thread 10 has generated an event
Cleaner: Size of the queue: 19
Cleaner: The thread 10 has generated an event
Cleaner: The thread 8 has generated an event
Cleaner: Size of the queue: 19
Cleaner: The thread 9 has generated an event
Cleaner: The thread 8 has generated an event
Cleaner: Size of the queue: 18
Cleaner: The thread 10 has generated an event
Cleaner: Size of the queue: 19
...


处理运行时异常(未检查异常)

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
package threadtest;
import java.lang.Thread.UncaughtExceptionHandler;
/**
* 在线程里处理不受控制的异常
*
* 当在一个线程里抛出一个异常,但是这个异常没有被捕获(这肯定是非检查异常),JVM 检查线程的相关方法是否有
* 设置一个未捕捉异常的处理者 。如果有,JVM 使用Thread 对象和 Exception 作为参数调用此方法 。如果线程
* 没有捕捉未捕获异常的处理者, 那么 JVM会把异常的 stack trace 写入操控台并结束任务。
*
* Thread 类有其他相关方法可以处理未捕获的异常。静态方法 setDefaultUncaughtExceptionHandler()
* 为应用里的所有线程对象建立异常 handler 。当一个未捕捉的异常在线程里被抛出,JVM会寻找此异常的3种
* 可能潜在的处理者(handler)。
* 首先, 它寻找这个未捕捉的线程对象的异常handle,如我们在在这个指南中学习的。如果这个handle 不存在,
* 那么JVM会在线程对象的ThreadGroup里寻找非捕捉异常的handler,如此例。如果此方法不存在,那么 JVM
* 会寻找默认非捕捉异常handle。如果没有一个handler存在, 那么 JVM会把异常的 stack trace 写入操控
* 台并结束任务。
*
*/
public class TaskWithUncaughtException07 implements Runnable {

@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("[" + i + "]");
if (i==5) {
Integer.parseInt("TTT"); //未检查异常(RuntimeException),这里没有将它捕获处理
}
}
}

public static void main(String[] args) {
Thread t = new Thread(new TaskWithUncaughtException07());

//为线程设置异常处理器
t.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("---------------异常信息-----------------");
System.out.println("Thread: " + t.getId() + " " + t.getState());
System.out.println("Exceprion: " + e.getClass().getName() + " " + e.getMessage());
e.printStackTrace(System.out);
}
});

t.start();
}
}


// 运行结果:
[0]
[1]
[2]
[3]
[4]
[5]
---------------异常信息-----------------
Thread: 8 RUNNABLE
Exceprion: java.lang.NumberFormatException For input string: "TTT"
java.lang.NumberFormatException: For input string: "TTT"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:492)
at java.lang.Integer.parseInt(Integer.java:527)
at threadtest.TaskWithUncaughtException07.run(TaskWithUncaughtException07.java:28)
at java.lang.Thread.run(Thread.java:745)


使用本地线程变量

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
110
111
112
113
114
115
116
117
118
119
120
package threadtest;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* 使用本地线程变量
*
*/
public class ThreadLocalTest08 {

public static void main(String[] args) {
//Task task = new UnsafeTask();
Task task = new SafeTask();
for (int i = 0; i < 10; i++) {
new Thread(task).start();
//
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}

}
}

}


abstract class Task implements Runnable {}

//此类startDate为非本地线程变量
//如果你创建一个类对象,实现Runnable接口,然后多个Thread对象使用同样的Runnable对象,全部的线程都共享同样的属性。
//这意味着,如果你在一个线程里改变一个属性,全部的线程都会受到这个改变的影响。
class UnsafeTask extends Task implements Runnable {
private Date startDate;

@Override
public void run() {
startDate = new Date();
System.out.printf("Starting Thread: %s : %s\n",Thread. currentThread().getId(),startDate);

try {
TimeUnit.SECONDS.sleep( (int)Math.rint(Math.random()*10));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("Thread Finished: %s : %s\n",Thread. currentThread().getId(),startDate);
}
}

//此类startDate为本地线程变量
//有时,你希望程序里的各个线程的属性不会被共享。 Java 并发 API提供了一个很清楚的机制叫本地线程变量。
//本地线程类还提供 remove() 方法,删除存储在线程本地变量里的值。
//另外,Java 并发 API 包括 InheritableThreadLocal 类提供线程创建线程的值的遗传性 。
//如果线程A有一个本地线程变量,然后它创建了另一个线程B,那么线程B将有与A相同的本地线程变量值。
//你可以覆盖 childValue() 方法来初始子线程的本地线程变量的值。 它接收父线程的本地线程变量作为参数。
class SafeTask extends Task implements Runnable {
private ThreadLocal<Date> startDate = new ThreadLocal<Date>() {
@Override
protected Date initialValue() {
return new Date();
}
};

@Override
public void run() {
System.out.printf("Starting Thread: %s : %s\n",Thread. currentThread().getId(),startDate.get());

try {
TimeUnit.SECONDS.sleep( (int)Math.rint(Math.random()*10));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("Thread Finished: %s : %s\n",Thread. currentThread().getId(),startDate.get());
}
}


//使用UnsafeTask执行结果
Starting Thread: 8 : Tue Mar 21 14:30:31 CST 2017
Starting Thread: 9 : Tue Mar 21 14:30:33 CST 2017
Starting Thread: 10 : Tue Mar 21 14:30:35 CST 2017
Thread Finished: 8 : Tue Mar 21 14:30:35 CST 2017
Starting Thread: 11 : Tue Mar 21 14:30:37 CST 2017
Thread Finished: 9 : Tue Mar 21 14:30:37 CST 2017
Thread Finished: 10 : Tue Mar 21 14:30:37 CST 2017
Starting Thread: 12 : Tue Mar 21 14:30:39 CST 2017
Thread Finished: 11 : Tue Mar 21 14:30:39 CST 2017
Starting Thread: 13 : Tue Mar 21 14:30:41 CST 2017
Starting Thread: 14 : Tue Mar 21 14:30:43 CST 2017
Thread Finished: 13 : Tue Mar 21 14:30:43 CST 2017
Starting Thread: 15 : Tue Mar 21 14:30:45 CST 2017
Thread Finished: 14 : Tue Mar 21 14:30:45 CST 2017
Starting Thread: 16 : Tue Mar 21 14:30:47 CST 2017
Thread Finished: 12 : Tue Mar 21 14:30:47 CST 2017
Starting Thread: 17 : Tue Mar 21 14:30:49 CST 2017
Thread Finished: 17 : Tue Mar 21 14:30:49 CST 2017
Thread Finished: 15 : Tue Mar 21 14:30:49 CST 2017
Thread Finished: 16 : Tue Mar 21 14:30:49 CST 2017

//使用SafeTask执行结果
Starting Thread: 8 : Tue Mar 21 15:11:10 CST 2017
Starting Thread: 9 : Tue Mar 21 15:11:12 CST 2017
Thread Finished: 9 : Tue Mar 21 15:11:12 CST 2017
Starting Thread: 10 : Tue Mar 21 15:11:14 CST 2017
Starting Thread: 11 : Tue Mar 21 15:11:16 CST 2017
Thread Finished: 11 : Tue Mar 21 15:11:16 CST 2017
Starting Thread: 12 : Tue Mar 21 15:11:18 CST 2017
Thread Finished: 10 : Tue Mar 21 15:11:14 CST 2017
Thread Finished: 12 : Tue Mar 21 15:11:18 CST 2017
Thread Finished: 8 : Tue Mar 21 15:11:10 CST 2017
Starting Thread: 13 : Tue Mar 21 15:11:20 CST 2017
Starting Thread: 14 : Tue Mar 21 15:11:22 CST 2017
Thread Finished: 13 : Tue Mar 21 15:11:20 CST 2017
Starting Thread: 15 : Tue Mar 21 15:11:24 CST 2017
Starting Thread: 16 : Tue Mar 21 15:11:26 CST 2017
Thread Finished: 15 : Tue Mar 21 15:11:24 CST 2017
Starting Thread: 17 : Tue Mar 21 15:11:28 CST 2017
Thread Finished: 14 : Tue Mar 21 15:11:22 CST 2017
Thread Finished: 17 : Tue Mar 21 15:11:28 CST 2017
Thread Finished: 16 : Tue Mar 21 15:11:26 CST 2017


线程工厂

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
package threadtest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
/**
* 线程工厂
* @author zhangqingli
*
*/
public class MyThreadFactory09 implements ThreadFactory {
private String name;
private int threadNum;
private List<String> status;

public MyThreadFactory09(String name) {
this.name = name;
this.threadNum = 0;
status = new ArrayList<String>();
}

@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, name+"-Thread-"+threadNum);
threadNum++;
status.add(String.format("created thread %d with name %s on %s\n",
t.getId(),t.getName(),new Date()));
return t;
}

public String getStatus() {
return status.toString();
}


public static void main(String[] args) {
MyThreadFactory09 tf = new MyThreadFactory09("MyThreadFactory");
MyTask task = new MyTask();
System.out.println("Starting the Threads\n");
for (int i = 0; i < 10; i++) {
tf.newThread(task).start();
}

System.out.printf("Factory stats:\n");
System.out.printf("%s\n",tf.getStatus());
}
}


class MyTask implements Runnable {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

}


//执行结果
Starting the Threads

Factory stats:
[created thread 8 with name MyThreadFactory-Thread-0 on Tue Mar 21 15:16:41 CST 2017
, created thread 9 with name MyThreadFactory-Thread-1 on Tue Mar 21 15:16:41 CST 2017
, created thread 10 with name MyThreadFactory-Thread-2 on Tue Mar 21 15:16:41 CST 2017
, created thread 11 with name MyThreadFactory-Thread-3 on Tue Mar 21 15:16:41 CST 2017
, created thread 12 with name MyThreadFactory-Thread-4 on Tue Mar 21 15:16:41 CST 2017
, created thread 13 with name MyThreadFactory-Thread-5 on Tue Mar 21 15:16:41 CST 2017
, created thread 14 with name MyThreadFactory-Thread-6 on Tue Mar 21 15:16:41 CST 2017
, created thread 15 with name MyThreadFactory-Thread-7 on Tue Mar 21 15:16:41 CST 2017
, created thread 16 with name MyThreadFactory-Thread-8 on Tue Mar 21 15:16:41 CST 2017
, created thread 17 with name MyThreadFactory-Thread-9 on Tue Mar 21 15:16:41 CST 2017
]


安全共享数居

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
package threadtest;
import java.util.Random;
import java.util.concurrent.TimeUnit;
/**
* 安全共享数居(安全同步数据)
* 只有操作公共资源的原子操作,才是需要加锁的,如果不是就没有加锁的必要。
*/
public class SynchronizedTest10 implements Runnable {
private int count = 10;

@Override
public void run() {
while (count>0) {
//一个原子操作
synchronized (SynchronizedTest10.class) {
System.out.println(Thread.currentThread().getName() + ": " + count);
count--;
}

try {
TimeUnit.SECONDS.sleep(new Random().nextInt(3));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public static void main(String[] args) {
SynchronizedTest10 s = new SynchronizedTest10();

for (int i = 0; i < 3; i++) {
new Thread(s).start();
}
}
}


//加锁执行结果:
Thread-0: 10
Thread-2: 9
Thread-1: 8
Thread-1: 7
Thread-1: 6
Thread-0: 5
Thread-2: 4
Thread-1: 3
Thread-2: 2
Thread-0: 1

//不加锁执行结果:
Thread-0: 10
Thread-2: 10
Thread-1: 10
Thread-0: 7
Thread-0: 6
Thread-2: 5
Thread-1: 5
Thread-1: 3
Thread-0: 2
Thread-2: 1


多个对象多个锁

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
package threadtest;
/**
* 多个对象多个锁
*/
public class SynchronizedTest11 {
public static void main(String[] args) {
/*
LoginServlet loginServlet = new LoginServlet();
new Thread(new LoginTask(loginServlet, "a")).start();
new Thread(new LoginTask(loginServlet, "b")).start();
//执行结果
login success!
username: a
login fail!
username: b
*/

LoginServlet loginServlet01 = new LoginServlet();
LoginServlet loginServlet02 = new LoginServlet();
new Thread(new LoginTask(loginServlet01, "a")).start();
new Thread(new LoginTask(loginServlet02, "b")).start();
//执行结果
//login success!
//login fail!
//username: b
//username: a
//[分析]
//两个线程分别访问同一个类的两个不同实例的相同名称的同步方法,效果是以异步方式执行的。
//本类由于是创建了两个业务对象,在系统中产生了两个锁,所以运行的结果是异步的。
//[注]
//如果把loginServlet的login方法改成synchronized static类型的,那么这个方法的锁
//类型就是类对象LoginServlet.class,由于它在JVM中只有一份,因此在该例中执行的效果
//仍是同步的。
}
}


class LoginTask implements Runnable {
private LoginServlet loginServlet;
private String username;

public LoginTask(LoginServlet loginServlet, String username) {
this.loginServlet = loginServlet;
this.username = username;
}

@Override
public void run() {
loginServlet.login(username);
}
}

class LoginServlet {
public synchronized void login(String username) {
try {
if ("a".equals(username)) {
System.out.println("login success!");
Thread.sleep(2000);
} else {
System.out.println("login fail!");
}
System.out.println("username: " + username);
} catch (Exception e) {
e.printStackTrace();
}
}
}


可重入锁

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
package threadtest;
import java.util.concurrent.TimeUnit;
/**
* 可重入锁
* 可重入锁的概念是:自己可以再次获取自己的内部锁,比如线程A获得了某个对象锁,此时
* 它的这个对象锁还没有释放,当它再次想获取这个对象锁的时候是可以获取的。
*
* 父子可重入锁
* 当存在父子类继承关系时,子类完全可以通过可重入锁调用父类的同步方法。
* 下面的就是一个父子可重入锁的演示。
*
*/
public class SynchronizedTest12 {
public static void main(String[] args) {
B b = new B();
new Thread(new MyThread(b)).start();
new Thread(new MyThread(b)).start();
//执行结果
//Thread: 8: b.bbb
//Thread: 8: a.aaa
//Thread: 9: b.bbb
//Thread: 9: a.aaa
}
}

class A {
public synchronized void aaa() {
System.out.println("Thread: " + Thread.currentThread().getId() + ": a.aaa");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

class B extends A {
public synchronized void bbb() {
System.out.println("Thread: " + Thread.currentThread().getId() + ": b.bbb");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
super.aaa();
}
}

class MyThread implements Runnable {
private B b;

public MyThread(B b) {
this.b = b;
}

@Override
public void run() {
b.bbb();
}
}


volatile关键字

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
package threadtest;
import java.util.concurrent.TimeUnit;
/**
* 1. volatile关键字解决的是数据在多个线程之间的可见性(不保证被操作数据的原子一致性),
* 而synchronized关键字解决的是操作的原子性,而且synchronized除了保证数据操作的
* 原子性,也将线程工作内存中的私有变量与主内存中的公共变量同步。
*
* 2. 主内存(=物理内存),线程工作内存(=CPU高速缓存)
* 被volatile修饰的变量保证了数据在多个不同线程之间的同步性,原理如下:
* volatile修饰符使被它修饰的变量对应的CPU高速缓存区(L1、L2)失效,
* 当volatile变量在线程A中被修改后,线程A会将其工作内存中的被修改
* 后的volatile变量写入主内存中,然后发送信号通知其他线程从主内存中
* 同步最新的值到工作内存,这样就保证了线程间变量数据的可见性。
*
*/
public class VolatileTest13 {
public static void main(String[] args) {
MyTask02 task = new MyTask02();
for (int i = 0; i < 10; i++) {
new Thread(task).start();
}
//
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
//
task.setInterrupted(true);
}
}

class MyTask02 implements Runnable {
private volatile boolean isInterrupted = false;

public boolean isInterrupted() {
return isInterrupted;
}
public void setInterrupted(boolean isInterrupted) {
this.isInterrupted = isInterrupted;
}

@Override
public void run() {
while (true) {
System.out.println("Thread: " + Thread.currentThread().getId() + " running!");
if (isInterrupted) {
break;
}
}
System.out.println("Thread: " + Thread.currentThread().getId() + " end!");
}
}
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
package threadtest;
/**
* 验证volatile不具有操作原子性
*
*/
public class VolatileTest14 {

public static void main(String[] args) {

MyThread03 thread03 = new MyThread03();

for (int i = 0; i < 10; i++) {
new Thread(thread03).start();
}
}
}

class MyThread03 implements Runnable {
public volatile int count = 0;

public synchronized void incr() {
try {
count++;
System.out.println(Thread.currentThread().getId() + ": " + count);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

@Override
public void run() {
incr();
}
}


//加锁执行结果:
8: 1
17: 2
16: 3
15: 4
14: 5
13: 6
12: 7
11: 8
10: 9
9: 10

//不加锁执行结果:
9: 2
12: 5
13: 6
11: 4
10: 3
8: 2
14: 7
15: 8
16: 9
17: 10