一,概念

当代操作系统中,可以独立并发执行的基本单元。

轻量:占用系统资源少

独立:操作系统中可以陆地调度和分派的基本单位

共享:共享进程中的资源


二,实现线程

更推荐集成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