一,概念
当代操作系统中,可以独立并发执行的基本单元。
轻量:占用系统资源少
独立:操作系统中可以陆地调度和分派的基本单位
共享:共享进程中的资源
二,实现线程
更推荐集成Runnable接口方式?
三,线程生命周期
新建:线程刚刚创建完毕
可运行:启动线程后
运行:操作系统调度中
阻塞/等待:等待资源或者时间片
消亡:退出run方法
四,常用API
静态 针对当前进程
currentThread
yield
sleep
实例方法 针对指定线程
start
setPriority/getPriority(1-10 不设置是5 不一定高优先级就能先执行)
setName/getName
setDaemon/isDaemon(守护线程是其他线程结束之后自动消亡的线程)
五,线程同步
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
|
/*
* DESCRIPTION :
* USER : zhouhui
* DATE : 2017/8/1 15:50
*/
public class SynchronizedTest {
/**
* method1:对方法进行锁
*/
public synchronized void method1(){
}
/**
* method2:对当前对象锁
*/
public void method2(){
synchronized (this){
}
}
/**
*method3:对当前对象锁
*/
public void method3(){
synchronized (SynchronizedTest.this){
}
}
/**
*method4:对静态方法锁
* 静态方法属于类,所以是对类上锁
*/
public synchronized static void method4(){
}
/**
*method5:对class锁
*/
public static void method5(){
synchronized (SynchronizedTest.class){
}
}
/**
* method6:对成员变量锁
*/
private
Integer i =
0
;
public
void
method6(){
synchronized
(i){
}
}
}
|
Java语法规定,任何线程执行同步方法、同步代码块 之前,必须先获取对应的监视器。
其中method1,method2,method3都是对当前对象上锁。
method4,method5对当前类上锁
method6是对属性上锁。
对方法上锁和对代码块上锁的区别是,如果方法太大,对方法上锁的开销要大的多。
method2和method6的区别:
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
|
public
class
Test {
public
static
void
main(String[] args) {
Data data =
new
Data();
new
Thread(
new
MyRunnable(data),
"A"
).start();
new
Thread(
new
MyRunnable(data),
"B"
).start();
}
}
class
Data{
private
Integer i =
0
;
public
void
show(){
while
(
true
){
synchronized
(i){
if
(i ==
30
){
break
;
}
System.out.println(Thread.currentThread().getName() +
" Before :"
+ i);
try
{
Thread.sleep(
100
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
i ++;
System.out.println(Thread.currentThread().getName() +
" After :"
+ i);
}
}
}
}
class
MyRunnable
implements
Runnable{
private
Data data;
public
MyRunnable(Data data){
this
.data = data;
}
public
void
run() {
data.show();
}
}
|
synchronized (i){
和
synchronized (this){
会产生不同的结果。
对this上锁能够正常的在30时停止,对i上锁会打印如下:
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
|
A Before :
0
A After :
1
B Before :
1
A Before :
1
A After :
2
A Before :
2
B After :
3
B Before :
3
B After :
4
A After :
5
B Before :
5
B After :
6
B Before :
6
A Before :
6
A After :
7
A Before :
7
B After :
8
B Before :
8
B After :
9
A After :
9
B Before :
9
B After :
10
B Before :
10
A Before :
10
A After :
11
A Before :
12
B After :
12
A After :
13
B Before :
13
A Before :
13
A After :
15
B After :
15
A Before :
15
A After :
16
B Before :
16
A Before :
16
A After :
17
A Before :
17
B After :
18
B Before :
18
A After :
19
A Before :
19
B After :
20
B Before :
20
A After :
21
A Before :
21
B After :
22
B Before :
22
A After :
23
A Before :
23
B After :
24
B Before :
24
A After :
25
A Before :
25
B After :
26
B Before :
26
A After :
27
A Before :
27
B After :
28
B Before :
28
A After :
29
A Before :
29
B After :
30
A After :
31
A Before :
31
A After :
32
A Before :
32
A After :
33
A Before :
33
A After :
34
A Before :
34
A After :
35
A Before :
35
|
但是有时候是可以成功的。
如果对i上锁,能够保证同一时间只能一个线程对i进行操作。如果一个线程能够在另外一个线程i++之前获得i那么,他是能够正常i==30停止的,但是如果在另外一个线程i++之后获得i那么,他就会直接跳过30,而继续运行。
对this上锁,意味着对整个对象上锁,只能一个线程操作代码块,保证数据的完整性。
六,线程间通信
Object对象提供了wait() notify() notifyAll()方法,被所有子类继承。
wait()获得当前对象锁的线程,释放掉当前的锁,无限期的等待,必须被其他的线程唤醒。
notify() 唤醒任意一个waiting的线程到ready状态,是否变成running状态,还需要线程调度器的调度。
notifyAll()唤醒所有的waiting的线程到ready状态。
线程间的通信其实就是停止和唤醒的过程。
以下代码实现两个线程对同一个对象的+1和-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
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
|
/*
* DESCRIPTION :
* USER : zhouhui
* DATE : 2017/8/1 17:28
*/
public
class
NumberHolder {
private
int
number;
public
synchronized
void
increase() {
if
(
0
!= number) {
try
{
wait();
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
// 能执行到这里说明已经被唤醒
// 并且number为0
number++;
System.out.println(number);
// 通知在等待的线程
notify();
}
public
synchronized
void
decrease() {
if
(
0
== number) {
try
{
wait();
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
// 能执行到这里说明已经被唤醒
// 并且number不为0
number--;
System.out.println(number);
notify();
}
}
class
IncreaseThread
extends
Thread {
private
NumberHolder numberHolder;
public
IncreaseThread(NumberHolder numberHolder) {
this
.numberHolder = numberHolder;
}
@Override
public
void
run() {
for
(
int
i =
0
; i <
20
; ++i) {
// 进行一定的延时
try
{
Thread.sleep((
long
) Math.random() *
1000
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
// 进行增加操作
numberHolder.increase();
}
}
}
class
DecreaseThread
extends
Thread {
private
NumberHolder numberHolder;
public
DecreaseThread(NumberHolder numberHolder) {
this
.numberHolder = numberHolder;
}
@Override
public
void
run() {
for
(
int
i =
0
; i <
20
; ++i) {
// 进行一定的延时
try
{
Thread.sleep((
long
) Math.random() *
1000
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
// 进行减少操作
numberHolder.decrease();
}
}
}
class
NumberTest {
public
static
void
main(String[] args) {
NumberHolder numberHolder =
new
NumberHolder();
Thread t1 =
new
IncreaseThread(numberHolder);
Thread t2 =
new
DecreaseThread(numberHolder);
t1.start();
t2.start();
}
}
|
打印结果:
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
|
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
|