------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

    线程间的通信:简单来说,就是多个线程在操作同一资源,但操作的动作不同。

  试想一下,对于同一个资源做不同的操作,这势必会在操作的过程中产生矛盾。为了避免这种情况的发生,就需要用的synchronized来保证,每次对共享资源的操作,只能是一条线程在进行。在用到同步的时候,就会因需求问题用到wait()、notify()、notifyAll()这三个方法。

  wait()方法:作用是使调用线程自动释放CPU使用权,从而使线程本身进入线程池继续等待。

  notify()方法:由运行的线程唤醒线程池中排在最前面的等待线程,使该线程具有使用CPU的资格。

  notifyAll()方法:由运行的线程唤醒线程池中的所有等待线程。

  因为三个方法都需以对持有(锁)监视器的对象操作,也就使他们只能在同步中使用,因为只有同步中才会出现锁这个概念。而通过查阅API,我们很容易就发现这三个方法都被定义在Object类当中,那么这些操作锁的方法为什么会被定义在Object类中呢?我们可以这样理解,同步中对于锁的标志位可以是任意的特有对象,而这三个方法都是操作锁的,也就是说他们可以操作任何对象,Java中能操作任何对象的类也只有Object类了。

  虽然有这些方法来使同步机制更加完善,但是对于某些情况同步机制并不能完美的完成相应的功能。

  针对以下代码:

 1 *
 2  * 生产者消费者问题
 3  */
 4 public class ProducerConsumerDemo{
 5     public static void main(String[] args){
 6         Resource r = new Resource();
 7         Producer pro = new Producer(r);
 8         Consumer con = new Consumer(r);
 9
10         Thread t1 = new Thread(pro);
11         Thread t3 = new Thread(pro);
12         Thread t2 = new Thread(con);
13         Thread t4 = new Thread(con);
14
15         t1.start();
16         t2.start();
17         t3.start();
18         t4.start();
19     }
20 }
21 //定义共享的资源类
22 class Resource{
23     private String name;
24     private int count = 1;
25     private boolean flag = false;
26
27     public synchronized void set(String name){
28         while(flag)
29             try{
30                 this.wait();
31             }catch(Exception e){
32
33             }
34         this.name = name+"--"+count++;
35         System.out.println(Thread.currentThread().getName()+"---生产者---"+this.name);
36         flag = true;
37         this.notifyAll();
38     }
39     public synchronized void out(){
40         while(!flag)
41             try{
42                 wait();
43             }catch(Exception e){
44             }
45         System.out.println(Thread.currentThread().getName()+"-----消费者-----"+this.name);
46         flag = false;
47         this.notifyAll();
48     }
49 }
50 //定义生产者类
51 class Producer implements Runnable{
52     private Resource res;
53     Producer(Resource res){
54         this.res = res;
55     }
56     public void run(){
57         while(true){
58             res.set("+商品+");
59         }
60     }
61 }
62 //定义消费者类
63 class Consumer implements Runnable{
64     private Resource res;
65     Consumer(Resource res){
66         this.res = res;
67     }
68     public void run(){
69         while(true){
70             res.out();
71         }
72     }
73 }

  在这个类中虽然可以初步满足生产者消费者这一功能需求,但我们可以发现在代码中我们用了notifyAll()这个方法,这个方法每运行一次将会把所有的等待状态的线程全部唤醒,这会给计算机带来很大的耗费,这种情况显然并不是我们所期望的。

   针对上述问题,官方在JDK1.5版本中进行了升级:

  * 引进了Lock接口从而替代了synchronized * 用Condition 替代了 Object监视器方法这样做的好处就是:一定程度上简化了同步代码的编写;一个Condition对象可以对不同锁进行操作,而且可以根据需求对特定的线程进行唤醒。而同时也要注意:一定要在对应的程序代码尾部执行释放锁的操作。  下面是通过运用Lock和Condition改进后的代码:
 1 import java.util.concurrent.locks.Condition;
 2 import java.util.concurrent.locks.ReentrantLock;
 3
 4 /*
 5  * 生产者消费者问题
 6  */
 7 public class ProducerConsumerDemo2{
 8     public static void main(String[] args){
 9         Resource2 r = new Resource2();
10         Producer2 pro = new Producer2(r);
11         Consumer2 con = new Consumer2(r);
12
13         Thread t1 = new Thread(pro);
14         Thread t3 = new Thread(pro);
15         Thread t2 = new Thread(con);
16         Thread t4 = new Thread(con);
17
18         t1.start();
19         t2.start();
20         t3.start();
21         t4.start();
22     }
23 }
24 //定义共有的资源
25 class Resource2{
26      private String name;
27      private int count = 1;
28      private boolean flag = false;
29
30      private ReentrantLock lock = new ReentrantLock();
31      Condition c_pro = lock.newCondition();
32      Condition c_con = lock.newCondition();
33
34     public void set(String name) throws InterruptedException{
35         lock.lock();
36         try{
37             while(flag)
38                     c_pro.await();
39             this.name = name+"--"+count++;
40             System.out.println(Thread.currentThread().getName()+"---生产者---"+this.name);
41             flag = true;
42             c_con.signal();
43         }finally{
44             lock.unlock();
45         }
46     }
47     public void out() throws InterruptedException{
48         lock.lock();
49         try{
50             while(!flag)
51                 c_con.await();
52             System.out.println(Thread.currentThread().getName()+"-----消费者-----"+this.name);
53             flag = false;
54             c_pro.signal();
55         }finally{
56             lock.unlock();
57         }
58     }
59 }
60 //定义生产者
61 class Producer2 implements Runnable{
62     private Resource2 res;
63     Producer2(Resource2 r){
64         this.res = r;
65     }
66     public void run(){
67         while(true){
68             try {
69                 res.set("+商品+");
70             } catch (InterruptedException e) {
71                 // TODO Auto-generated catch block
72                 e.printStackTrace();
73             }
74         }
75     }
76 }
77 //定义消费者
78 class Consumer2 implements Runnable{
79     private Resource2 res;
80     Consumer2(Resource2 r){
81         this.res = r;
82     }
83     public void run(){
84         while(true){
85             try {
86                 res.out();
87             } catch (InterruptedException e) {
88                 e.printStackTrace();
89             }
90         }
91     }
92 }

 接下来是关于线程的停止:   1、正常的情况是,等待线程运行完,自动释放CPU占用权。这种方式也是最为安全的。     2、多线程中常用循环控制语句,我们可以通过设置标志位,来使线程在不满足条件的情况下自动释放CPU资源,停止运行。   3、对于占有资源但却因为某种原因进入冻结的线程,我们可以使用interrupt()方法来打断其状态,进而使之可以正常运行释放资源。 设置守护进程的方法:通过调用SetDaemon()方法,可以把对应进程设置成守护进程或者是用户进程。

  join()方法:作用是长期占有CPU使用权。原理是:当A线程执行到了B线程的join方法时,A就会等待,等B线程执行完,A才会执行。Join可以用来临时加入线程执行。   代码示例:
 1 class Demo implements Runnable{
 2     public void run(){
 3         for(int x=0; x<20; x++){
 4             System.out.println(Thread.currentThread().getName()+"---"+x);
 5         }
 6     }
 7 }
 8 public class JoinTest {
 9     public static void main(String[] args) throws InterruptedException {
10         Demo d = new Demo();
11         Thread t1 = new Thread(d);
12         Thread t2 = new Thread(d);
13
14         t1.start();
15         t1.join();
16         t2.start();
17
18         for(int x=0; x<30; x++){
19             System.out.println("main--"+x);
20         }
21         System.out.println("over");
22     }
23 }

  执行结果:
 1 Thread-0---0
 2 Thread-0---1
 3 Thread-0---2
 4 Thread-0---3
 5 Thread-0---4
 6 Thread-0---5
 7 Thread-0---6
 8 Thread-0---7
 9 Thread-0---8
10 Thread-0---9
11 Thread-0---10
12 Thread-0---11
13 Thread-0---12
14 Thread-0---13
15 Thread-0---14
16 Thread-0---15
17 Thread-0---16
18 Thread-0---17
19 Thread-0---18
20 Thread-0---19
21 main--0
22 Thread-1---0
23 main--1
24 Thread-1---1
25 Thread-1---2
26 Thread-1---3
27 Thread-1---4
28 Thread-1---5
29 Thread-1---6
30 Thread-1---7
31 main--2
32 Thread-1---8
33 Thread-1---9
34 main--3
35 Thread-1---10
36 main--4
37 Thread-1---11
38 Thread-1---12
39 Thread-1---13
40 Thread-1---14
41 Thread-1---15
42 Thread-1---16
43 main--5
44 main--6
45 main--7
46 main--8
47 main--9
48 main--10
49 main--11
50 main--12
51 main--13
52 main--14
53 main--15
54 main--16
55 main--17
56 Thread-1---17
57 main--18
58 Thread-1---18
59 main--19
60 Thread-1---19
61 main--20
62 main--21
63 main--22
64 main--23
65 main--24
66 main--25
67 main--26
68 main--27
69 main--28
70 main--29
71 over

  我们可以发现只有当线程t1执行完以后,main线程才会和t2线程继续强度CPU的使用权,进而相继输出。所以可以理解为join()方法是线程具有了长期占有CPU的资格。

    关于线程优先级的知识:

     1、线程的优先级设置范围为(1-10);

       2、线程默认的优先级是5;

           3、我们可以通过SetPriority(1-10)来对线程的优先级进行设置。

     4、因为相邻的优先级效果差别很小,说以一般提倡对优先级设置一下几个值:Thread.MAX_PRIORITY 10 ;Thread.MIN_PRIORITY 1;Thread.NORM_PRIORITY 5
   yield()方法:暂停当前正在执行的线程,转而去执行其它线程。 
开发中应用:保证以下三个代码同时运行。
案例代码:
 1 new Thread(){
 2       for(int x=0;x<100;x++){
 3          sop(Thread.currentThread().getName())
 4       }
 5 }.start();
 6
 7       for(int x=0;x<100;x++){
 8          sop(Thread.currentThread().getName())
 9       }
10
11 Runnable r=new Runnable(){
12    public voud run(){
13       for(int x=0;x<100;x++){
14          sop(Thread.currentThread().getName())
15       }
16    }
17 };
18
19 new Thread(r).start();

转载于:https://www.cnblogs.com/shadowW-W/p/4647051.html

黑马程序员——java基础---多线程(二)相关推荐

  1. 黑马程序员——Java基础---多线程

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 多线程 一.概述 说起多线程,我们就需要首先来谈谈什么叫做进程.所谓进程,就是在计算机上正在进行 ...

  2. 黑马程序员 java基础复习二 之面向对象

    ---------------------------------------------------------------- android培训.java培训.期待与您交流! ---------- ...

  3. 黑马程序员---java基础------------------多线程

    线程:就是进程中的一个独立的控制单元.线程在控制着进程的执行. 线程的创建 一:继承Thread类.步骤: 1,定义类继承Thread. 2,复写Thread类中的run方法.      目的:将自定 ...

  4. 黑马程序员JAVA基础-多线程

    ------- android培训.java培训.期待与您交流! ---------- 线程: 线程是进程中的一个独立的控制单元 线程在控制着进程的执行 一个进程中至少有一个线程 线程的创建 第一种方 ...

  5. 黑马 程序员——Java基础---流程控制

    黑马程序员--Java基础---流程控制 ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------ 一.概述 Java提供了两种基本的流程控制结构:分支结构 ...

  6. 黑马 程序员——Java基础---IO(下)

    黑马程序员--Java基础---IO(下) ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------ 一.概述 Java除了基本的字节流.字符流之外,还提供 ...

  7. 黑马程序员-Java基础:面向对象(上)

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 一.面向对象概述 当需求单一,或者简单时,我们一步一步去操作没问题,并且效率也挺高.可随着需求的 ...

  8. 黑马程序员——java的多线程

    ------- android培训.java培训.期待与您交流! ---------- 前言:通过观看毕向东老师的java基础视频,查漏补缺,将一些自己掌握的还不牢固的知识写出来,希望和大家交流分享. ...

  9. 黑马程序员--Java基础加强篇

    开发工具使用 --------------------------------------------------------------------------------------------- ...

最新文章

  1. C++中的虚函数表介绍
  2. Timer计时不准确的解决方案 每次都重新调整,修正误差
  3. 视频: 猫和老鼠真实版
  4. ntpdate[27350]: no server suitable for synchronization found
  5. 区块链BaaS云服务(37)荷兰Techruption 区块链
  6. Xcode没有pch文件
  7. [Unity3d]多个摄像机叠加效果
  8. (待完成)qbxt2019.05 总结2 - 数位DP
  9. Python环境下如何安装爬虫需求的一些库
  10. 运维之Linux秋招重点(根据面经和常见笔试题总结,持续更新)
  11. paraview编译
  12. css水波纹-雷达扩散效果
  13. 西安邮电考研计算机复试线,2020西安邮电大学考研复试分数线已公布
  14. Web 前端学习之表单制作、网页超链接
  15. 激活函数σ、tanh、relu、Leakyrelu、LR_BP反向传播推导
  16. 作为一名软件测试人员,有哪些网站是你应该多多关注的,哪些书籍是你必须要看的?
  17. 关于TextView中修改部分字体颜色、大小方法的总结
  18. 渣基础:比照Hawstein学Cracking the coding interview(1)
  19. 【基础教程】法线贴图原理与制作 粗解
  20. IOT技术专家伏治军谈IOT技术发展趋势

热门文章

  1. jQuery动画高级用法(上)——详解animation中的.queue()函数
  2. http://www.gamesofdesire.com/
  3. VMware找不到父磁盘 父虚拟磁盘在子虚拟磁盘创建之后被修改过。父虚拟磁盘的内容 ID 与子虚拟磁盘中对应的父内容 ID 不匹配
  4. 嵌入式 开发板 Linux 挂载ubifs
  5. Linux 查询 OS、CPU、内存、硬盘信息
  6. 荣耀手表2鸿蒙,鸿蒙2.0曝光 计划在明年用于手表手环上
  7. oracle虚拟机导入表,在Linux虚拟机上安装Oracle数据库超完整版!)
  8. python编写函数、计算三个数的最大公约数_Python实现利用最大公约数求三个正整数的最小公倍数示例...
  9. 回顾 | Apache Flink 1.13 新版本 x 互娱实践分享 Meetup · 北京站精彩回顾 (附 PPT 下载)
  10. 【深度探讨】阿里巴巴万级规模 K8s 集群全局高可用体系之美