线程通信
线程间通讯:其实就是多个线程在操作同一个资源,但是操作的动作不同。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class ProducerConsumerDemo
{
public static void main ( String [] args )
{
Resource r = new Resource ();
Producer pro = new Producer ( r );
Consumer con = new Consumer ( r );
Thread t1 = new Thread ( pro );
Thread t2 = new Thread ( pro );
Thread t3 = new Thread ( con );
Thread t4 = new Thread ( con );
t1 . start ();
t2 . start ();
t3 . start ();
t4 . start ();
}
}
Copy 对于多个生产者和消费者。 为什么要定义 while 判断标记。
原因:让被唤醒的线程再一次判断标记。
为什么定义=notifyAll=, 因为需要唤醒对方线程。
因为只用 notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。
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
class Resource
{
private String name ;
private int count = 1 ;
private boolean flag = false ;
// t1 t2
public synchronized void set ( String name )
{
while ( flag )
try { this . wait ();} catch ( Exception e ){} //t1(放弃资格) t2(获取资格)
this . name = name + "--" + count ++;
System . out . println ( Thread . currentThread (). getName ()+ "...生产者.." + this . name );
flag = true ;
this . notifyAll ();
}
// t3 t4
public synchronized void out ()
{
while (! flag )
try { wait ();} catch ( Exception e ){} //t3(放弃资格) t4(放弃资格)
System . out . println ( Thread . currentThread (). getName ()+ "...消费者........." + this . name );
flag = false ;
this . notifyAll ();
}
}
class Producer implements Runnable
{
private Resource res ;
Producer ( Resource res )
{
this . res = res ;
}
public void run ()
{
while ( true )
{
res . set ( "+商品+" );
}
}
}
class Consumer implements Runnable
{
private Resource res ;
Consumer ( Resource res )
{
this . res = res ;
}
public void run ()
{
while ( true )
{
res . out ();
}
}
}
Copy 进程同步优化解决方案
JDK1.5 中提供了多线程升级解决方案。
将同步 Synchronized 替换成显式的 Lock 操作。 将 Object 中的 wait,notify
notifyAll,替换了 Condition 对象。 该对象可以 Lock 锁 进行获取。
该示例中,实现了本方只唤醒对方操作。
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
import java.util.concurrent.locks.* ;
class ProducerConsumerDemo2
{
public static void main ( String [] args )
{
Resource r = new Resource ();
Producer pro = new Producer ( r );
Consumer con = new Consumer ( r );
Thread t1 = new Thread ( pro );
Thread t2 = new Thread ( pro );
Thread t3 = new Thread ( con );
Thread t4 = new Thread ( con );
t1 . start ();
t2 . start ();
t3 . start ();
t4 . start ();
}
}
class Resource
{
private String name ;
private int count = 1 ;
private boolean flag = false ;
// t1 t2
private Lock lock = new ReentrantLock ();
private Condition condition_pro = lock . newCondition ();
private Condition condition_con = lock . newCondition ();
public void set ( String name ) throws InterruptedException
{
lock . lock ();
try
{
while ( flag )
condition_pro . await (); //t1,t2
this . name = name + "--" + count ++;
System . out . println ( Thread . currentThread (). getName ()+ "...生产者.." + this . name );
flag = true ;
condition_con . signal ();
}
finally
{
lock . unlock (); //释放锁的动作一定要执行。
}
}
// t3 t4
public void out () throws InterruptedException
{
lock . lock ();
try
{
while (! flag )
condition_con . await ();
System . out . println ( Thread . currentThread (). getName ()+ "...消费者........." + this . name );
flag = false ;
condition_pro . signal ();
}
finally
{
lock . unlock ();
}
}
}
class Producer implements Runnable
{
private Resource res ;
Producer ( Resource res )
{
this . res = res ;
}
public void run ()
{
while ( true )
{
try
{
res . set ( "+商品+" );
}
catch ( InterruptedException e )
{
}
}
}
}
class Consumer implements Runnable
{
private Resource res ;
Consumer ( Resource res )
{
this . res = res ;
}
public void run ()
{
while ( true )
{
try
{
res . out ();
}
catch ( InterruptedException e )
{
}
}
}
}
Copy
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
class Res
{
private String name ;
private String sex ;
private boolean flag = false ;
public synchronized void set ( String name , String sex )
{
if ( flag )
try { this . wait ();} catch ( Exception e ){}
this . name = name ;
this . sex = sex ;
flag = true ;
this . notify ();
}
public synchronized void out ()
{
if (! flag )
try { this . wait ();} catch ( Exception e ){}
System . out . println ( name + "........" + sex );
flag = false ;
this . notify ();
}
}
class Input implements Runnable
{
private Res r ;
Input ( Res r )
{
this . r = r ;
}
public void run ()
{
int x = 0 ;
while ( true )
{
if ( x == 0 )
r . set ( "mike" , "man" );
else
r . set ( "丽丽" , "女女女女女" );
x = ( x + 1 )% 2 ;
}
}
}
class Output implements Runnable
{
private Res r ;
Output ( Res r )
{
this . r = r ;
}
public void run ()
{
while ( true )
{
r . out ();
}
}
}
class InputOutputDemo2
{
public static void main ( String [] args )
{
Res r = new Res ();
new Thread ( new Input ( r )). start ();
new Thread ( new Output ( r )). start ();
/*
Input in = new Input(r);
Output out = new Output(r);
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
*/
}
}
Copy 等待的线程存放在线程池中 最先唤醒的是最先被冻结的线程
停止线程
stop 方法已经过时。
如何停止线程? 只有一种,run 方法结束。
开启多线程运行,运行代码通常是循环结构。
只要控制住循环,就可以让 run 方法结束,也就是线程结束。
特殊情况: 当线程处于了冻结状态。 就不会读取到标记。那么线程就不会结束。
当没有指定的方式让冻结的线程恢复到运行状态是,这时需要对冻结进行清除。
强制让线程恢复到运行状态中来。这样就可以操作标记让线程结束。
Thread 类提供该方法 interrupt()
;
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
class StopThread implements Runnable
{
private boolean flag = true ;
public void run ()
{
while ( flag )
{
System . out . println ( Thread . currentThread (). getName ()+ "....run" );
}
}
public void changeFlag ()
{
flag = false ;
}
}
class StopThreadDemo
{
public static void main ( String [] args )
{
StopThread st = new StopThread ();
Thread t1 = new Thread ( st );
Thread t2 = new Thread ( st );
t1 . setDaemon ( true );
t2 . setDaemon ( true );
t1 . start ();
t2 . start ();
int num = 0 ;
while ( true )
{
if ( num ++ == 60 )
{
//st.changeFlag();
//t1.interrupt();
//t2.interrupt();
break ;
}
System . out . println ( Thread . currentThread (). getName ()+ "......." + num );
}
System . out . println ( "over" );
}
}
Copy 守护进程
join:
当 A 线程执行到了 B 线程的.join()方法时,A就会等待。等 B 线程都执行完,A才会执行。
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
class Demo implements Runnable
{
public void run ()
{
for ( int x = 0 ; x < 70 ; x ++)
{
System . out . println ( Thread . currentThread (). toString ()+ "....." + x );
Thread . yield ();
}
}
}
class JoinDemo
{
public static void main ( String [] args ) throws Exception
{
Demo d = new Demo ();
Thread t1 = new Thread ( d );
Thread t2 = new Thread ( d );
t1 . start ();
//t1.setPriority(Thread.MAX_PRIORITY);
t2 . start ();
//t1.join();
for ( int x = 0 ; x < 80 ; x ++)
{
//System.out.println("main....."+x);
}
System . out . println ( "over" );
}
}
Copy 练习
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class MyThread extends Thread {
public void run (){
try {
Thread . currentThread (). sleep ( 3000 );
} catch ( InterruptedException e ) {
}
System . out . println ( "MyThread running" );
}
}
public class ThreadTest {
public static void main ( String argv []) {
MyThread t = new MyThread ();
t . run ();
t . start ();
System . out . println ( "Thread Test" );
}
}
Copy 代码分析过程:
MyThread t = new MyThread();
创建了一个线程。 t.run();
调用=MyThread=对象的=run()=方法。 这是只有一个线程在运行就是主线程。
当主线程执行到了=run()=方法中的=sleep(3000);=时。
这是主线程处于冻结状态。程序并没有任何执行。 当 3 秒过后,主线程打印了
=MyThread running=。 =run()=方法执行结束。
t.start();
开启了 t 线程。 有两种可能情况。 1. 第一种情况:
主线程在只执行了=t.start()=后,还具有执行权,继续往下执行,
打印了=Thread Test=。主线程结束。
t 线程获取执行权,调用自己的 run 方法。然后执行的=sleep(3000);=冻结 3 秒。
3 秒后,打印 MyThread running t 线程结束,整个程序结束。
第二种情况:
主线程执行到=t.start();=开启了 t 线程,t线程就直接获取到了执行权。
就调用自己的=run()=方法。
指定到=sleep(3000)=.t 线程冻结 3 秒,这是 t 线程就是释放了执行权。
那么主线程开始执行打印了=Thread Test=,主线程结束。
等到 3 秒后,t线程打印=MyThread running= ,然后 t 线程结束。 程序结束。
总结
线程间通信。
1
2
3
4
5
6
7
8
9
10
11
12
等待/唤醒机制。
也就是常见的生产者消费者问题。
1. 当多个生产者消费者出现时,
需要让获取执行权的线程判断标记。
通过while完成。
2. 需要将对方的线程唤醒。
仅仅用notify,是不可以的。因为有可能出现只唤醒本方。
有可能会导致,所有线程都等待。
所以可以通过notifyAll的形式来完成 。
Copy 这个程序有一个 bug。就是每次 notifyAll。都会唤醒本方。
可不可以只唤醒对方呢?
JDK1.5 版本提供了一些新的对象,优化了等待唤醒机制。
将 synchronized 替换成了 Lock 接口。 将隐式锁,升级成了显示锁。 Lock -
获取锁:lock(); -
释放锁:unlock();注意:释放的动作一定要执行,所以通常定义在 finally 中。 -
获取 Condition 对象:newCondition();
将 Object 中的 wait,notify,notifyAll 方法都替换成了 Condition 的 await,signal,signalAll。
和以前不同是:一个同步代码块具备一个锁,该所以具备自己的独立 wait 和 notify 方法。
现在是将 wait,notify 等方法,封装进一个特有的对象 Condition,而一个 Lock 锁上可以有多个 Condition 对象。
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
Lock lock = new ReentrantLock ();
Condition conA = lock . newCondition ();
Condition conB = lock . newCondition ();
con . await (); //生产,,消费
con . signal (); 生产
set ()
{
if ( flag )
conA . await (); //生产者,
code ......;
flag = true ;
conB . signal ();
}
out ()
{
if (! flag )
conB . await (); //消费者
code ....;
flag = false ;
conA . signal ();
}
Copy
wait 和 sleep 的区别: wait:释放 cpu 执行权,释放同步中锁。
sleep:释放 cpu 执行权,不释放同步中锁。
synchronized(锁) { wait(); }
停止线程:
1
2
3
4
5
6
7
8
**stop过时。**
原理:run方法结束。run方法中通常定义循环,指定控制住循环线程即可结束。
1. 定义结束标记。
2. 当线程处于了冻结状态,没有执行标记,程序一样无法结束。
这时可以循环,正常退出冻结状态,或者强制结束冻结状态。
强制结束冻结状态:interrupt();目的是线程强制从冻结状态恢复到运行状态。
但是会发生InterruptedException异常。
Copy
多线程重点: 1. 多线程的创建的两种方式,以及区别。
同步的特点。 同步的好处: 同步的弊端: 同步的前提:
同步的表现形式以及区别。 特例:static 同步函数锁是哪一个。
死锁代码要求写的出来。
线程间通信,看以上总结。
wait 和 sleep, yield()
: 临时暂停,可以让线程是释放执行权。
=yield()=方法 API:
`给调度程序的一个提示,当前线程愿意得到它当前的处理器的使用。调度程序可以自由地忽略这个提示。
产量是一个启发式的尝试,以改善线程之间的相对进展,否则将过度使用一个中央处理器。它的使用应结合详细的分析和基准,以确保它实际上有所需的效果。
使用这种方法是不恰当的。它可能是有用的调试或测试的目的,它可能有助于重现由于种族条件的错误。这也可能是有用的在设计并发控制结构如在 java.util.concurrent.locks 包的。
`