JAVASE_12_%多线程_线程通信

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唤醒,不然一直等待。
*********************************************************************** 

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()
代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
private  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,该方法必须在启动线程前调用.
1
2
3
4
t1.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();
         //===============================================================
     }
}
   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值