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
|
class
Res{
//同一个资源
String name;
String sex;
boolean
flag =
false
;
}
class
Input
implements
Runnable{
private
Res r ;
Input(Res r){
this
.r = r;
}
public
void
run(){
int
x =
0
;
while
(
true
){
synchronized
(r){
//保证同步的2个前提
if
(x==
0
){
r.name=
"mike"
;
r.sex=
"man"
;
}
else
{
r.name=
"丽丽"
;
r.sex =
"女女女女女"
;
}
x = (x+
1
)%
2
;
r.flag =
true
;
r.notify();
}
}
}
}
class
Output
implements
Runnable{
private
Res r ;
Output(Res r){
this
.r = r;
}
public
void
run(){
while
(
true
){
synchronized
(r){
System.out.println(r.name+
"...."
+r.sex);
}
}
}
}
class
InputOutputDemo{
public
static
void
main(String[] args) {
Res r =
new
Res();
Input in =
new
Input(r);
Output out =
new
Output(r);
Thread t1 =
new
Thread(in);
Thread t2 =
new
Thread(out);
t1.start();
t2.start();
}
}
|
2.等待唤醒机制
(一) 用wait和notify实现-----------在同步代码块中加标记flag=flag
wait();//有异常 flag = false时notify();flag =true时;//唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程notifyall();对象1.wait( ),对象1.notify()从类 java.lang.Object 继承的方法都是用在同步中,因为要对持有监视器(锁)的线程操作。(二) 等待的线程在哪?所以要使用在同步中,因为只有同步才具有锁
线程运行的时候,内存中会建立一个叫 线程池。等待的线程就存放在这里
(三)为什么这些操作线程的方法要定义在object类中呢?
***********************************************************************因为这些方法在操作同步中线程时,都必须要标识它们所操作线程持有的锁。只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒。不可以对不同锁中的线程进行notify唤醒。也就是说, 等待和唤醒必须是同一个锁而锁可以是任意对象,所以可以被任意对象调用的方法定义在object类中。
wait和sleep的区别?------面试------(2点)
1,
当然也可以在不获得锁时可以直接sleep,但wait的时候,必须是在获得同步锁的
2,wait:会释放获得的对象锁【同步锁即synchronized
】,并进入等待队列
sleep:的等待的时候,是不释放锁的,当然这是在sleep之前已经获得锁的前提下。
。
解析:
释放锁是释放同步锁,释放资源是释放CPU执行资源,票是同步代码操作的数据,不是所说的资源
sleep是占着CPU执行资源在那等待,过了指定的时间自动苏醒继续执行代码,
而wait是放弃CPU的执行资源让当前线程在那等待,并放弃同步锁,让其他线程可以来操作同步代码,
除非被notify或者notifyAll唤醒,不然一直等待。
***********************************************************************
5.停止线程
3.线程间通信--生产者消费者
对于多个生产者和消费者。会出现2个问题:1,为什么要定义while判断标记。
2,【死锁】为什么定义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
63
64
65
66
67
68
|
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();
}
}
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();
}
}
}
|
4.线程间通信--JDK升级版
生产者消费者1.5后的替代方案:
1.5版本后,提供了 显式的锁机制以及显式的锁 对象上的等待唤醒操作机制。同时将等待唤醒进行封装,封装完, 一个锁lock可以对应多个Condition对象JDK1.5 中提供了多线程升级解决方案。
|----java.util.concurrent.locks
|-----Condition接口
|------Lock接口
Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现 组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。代码示例:
jdk1.4 ---------> jdk1.5 synchronized 关键字
Lock接口
lock( )获取锁 同步代码块
unlock( )释放锁
newCondition() ============ ======= ============== Object
Condition接口 wait( )
await();//抛异常 notify( )
signal( )//唤醒 notifyAll( )
signalAll()
12345678910111213private
Lock myLock =
new
ReentrantLock();
//获取锁,ReentrantLock类实现了Lock接口
private
Condition con = myLock.newCondition();
//绑定到此Lock实例的新Condition实例
lock.lock();
//解锁
try
{
while
(flag ==
true
)
con.await();
//条件不允许---等待
//执行代码
flag =
true
;
con.signal();
//唤醒,
当唤醒本方的时候会出现死锁现象,解决方案是一个lock用2个Condition对象
}
finally
{
lock.unlock();
//如果try{}抛出异常导致解锁动作无法进行,所以释放锁的动作一定要执行。
}
该对象可以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
|
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();
//一个锁对应多个Condition对象
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.signalAll();
}
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){
}
}
}
}
|
5.停止线程
如何停止线程?
只有一种,run方法结束.
方法一: stop----已过时方法二:循环结构方法三:使用interrupt()方法,有异常InterruptedException
--------何时用到?
特殊情况:当线程处于了冻结状态。就不会读取到标记。那么线程就不会结束。当没有指定的方式让冻结的线程恢复到运行状态是,这时需要对冻结进行清除。强制让线程恢复到运行状态中来。这样就可以操作标记让线程结束。Thread类提供该方法 interrupt();
6.守护线程setDaemon()
守护线程,即后台线程,为非后台线程服务。如果前台线程全部结束,则后台线程也随即结束,然后JVM退出;否则后台的守护线程将一直执行。
public final void setDaemon(boolean on)----on - 如果为 true,则将该线程标记为守护线程。1,将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出.2,该方法必须在启动线程前调用.
1234t1.setDaemon(
true
);
t2.setDaemon(
true
);
t1.start();
t2.start();
7.jion方法
当A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完,A才会执行。join可以用来临时加入线程执行。t1.start();
t2.start();
t1.join();//t1要cpu执行权
和t1.start();
t1.join();
t2.start();
8.toString()和yield()
toString()----线程的字符串表示形式,包括线程名称、优先级和线程组yield()--------暂停当前正在执行的线程对象,并执行其他线程
优先级----代表抢资源的频率,1-10级,所有线程包括主线程默认优先级是5线程组----默认情况,谁开启该线程,该线程就属于次组java.lang.ThreadGroup类
9,当三段代码要求同时运行时
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
|
class
ThreadTest {
public
static
void
main(String[] args) {
//================================================
new
Thread(){
public
void
run(){
//
}
}.start();
//==================================================
for
(
int
x=
0
; x<
100
; x++)
{
System.out.println(Thread.currentThread().getName()+
"....."
+x);
}
//=====================================================
Runnable r =
new
Runnable()
{
public
void
run()
{
for
(
int
x=
0
; x<
100
; x++)
{
System.out.println(Thread.currentThread().getName()+
"....."
+x);
}
}
};
new
Thread(r).start();
//===============================================================
}
}
|