Java中线程共有5中状态:

  1. 新建:当创建一个线程对象时,新线程对象就处于新建状态,并获得除CPU外所需的资源。
  2. 就绪:当处于新建状态的线程被启动后,将进入线程队列等待CPU资源。这时它就具备了运行条件,一旦获得CPU资源,就可以脱离创建它的主线程独立运行。另外原来处于阻塞状态的线程结束阻塞状态后,也进入就绪状态。
  3. 运行:当一个就绪状态的线程获得CPU资源时,就进入了运行状态。每个线程对象都有一个run方法,一旦线程开始运行,就会自动运行该方法。run()中定义了具体的线程操作。
  4. 阻塞:一个正在运行的线程因为某种特殊的原因,比如遇到优先级高的线程、某种资源无法满足时就会让出CPU并停止自身的运行,进入阻塞状态。只有当引起阻塞的原因消除时,它才能重新进入就绪状态。
  5. 死亡:不具备继续运行能力的线程处于死亡状态。一般由两种情况引起:run()方法运行完毕;其他线程强制终止它。

就绪队列:处于就绪状态的线程都在就绪队列中等待CPU资源,而一般就绪队列中会有多个线程。为此,系统会给每一个线程分配一个优先级,优先级高的可以排在较前面的位置,能优先得到CPU资源。对于优先级相同的线程,一般按照先来先服务的原则调度。

进程和线程最大的区别在于进程是由操作系统来控制的,而线程是由进程来控制的,所以是由程序员来控制的。进程都是相互独立的,各自享有各自的内存空间。而一个进程中的多个线程是共享内存空间的,他们可以访问相同的变量和对象。本来这样的设计方便了线程间的通讯,但却带来了新的问题:多个线程同时访问一个变量可能出现意想不到的错误,如死锁。所以多线程操作要注意协调与配合,进行互斥和同步处理。

  • 互斥:当多个线程需要访问同一资源时,而这一资源在某一时刻只允许一个线程访问,那么这些线程就是互斥。如线程A需要读取变量count,而线程B会给count赋值,那边A和B是互斥的。
  • 同步:多个线程需要访问同一资源,而且需要相互配合才能正常工作,这些线程运行时就是一种同步关系。例如,A线程需要从缓冲区中读取数据,而B线程需要向缓冲区中写数据,但缓冲区的大小是固定的。
  • 临界区:为了实现线程间的互斥和同步,需要将共享资源放入一个区域,该区域一次只允许一个线程进入,该区域就被称为临界区域。线程在访问共享资源前需要进行检查,看自己是否有权访问资源,如果有权访问还要阻止其他线程进入该区域。该代码段就是临界区。
  • 死锁:若多个线程相互等待其他线程释放资源,而所有线程又都不释放自己所占的资源,从而导致相关线程处于永远等待的状态,这种现象称为线程死锁。

线程通讯

线程间互斥和同步必须使用信号量,Java中信号量需要用户自己管理,系统只提供了起到PV原语作用的方法:

  • void notify():唤醒在此对象监视器上等待的某一个线程.具体是哪一个可以认为是不确定的.
  • void notifyAll():唤醒在此对象监视器上等待的所有线程。
  • void wait():导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法.

wait会释放占有的资源(锁),notify和notifyAll不会释放占用的资源(锁).而线程睡眠(sleep)时,也都不会释放资源(锁)。

除了三个方法,还有一个常用的关键字:synchronized.

凡是被synchronized标志的资源,都是临界区,在同一时刻只能有一个线程能够进入该临界区。synchronized可以用于数据、方法,甚至是一段代码。synchronized也被称为“对象锁”,而且上面的三个方法都只能使用在由synchronized标志的代码块中,否则会发生如下异常:

java.lang.IllegalMonitorStateException: current thread not owner

synchronized是和一个锁对象关联的,一个对象只有一个锁。当程序运行到synchronized同步方法或代码块时就会检查锁,如果一个线程获得该锁,就没有其他线程可以获得锁,直到第一个线程释放(或返回)锁。这也意味着任何其他线程都不能进入该对象上的synchronized方法或代码块,直到该锁被释放。

如myThread.java文件代码:

public class myThread extends Thread {private static int count=0;private static Object o=new Object();//定义一个Object对象,用于锁
    @Overridepublic void run() {synchronized(o){for(int i=0;i<20;i++){count+=1;System.out.println("My name is "+this.getName()+" count= "+count);            try {sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}}public myThread(String arg0) {super(arg0);}
}

启动线程代码如下:

myThread tf=new myThread("first");
myThread ts=new myThread("secod");
tf.start();
ts.start();

执行的结果:

My name is secod count= 1
My name is secod count= 2
.....
.....
My name is secod count= 20
My name is first count= 21
My name is first count= 22
My name is first count= 23
.....
.....
My name is first count= 40

myThread.java文件中的for循环使用synchronized标志,是临界区,第一次进入的是secod线程,知道执行完毕释放锁,first线程才进入临界区。

synchronized可以用于方法、数据,甚至是代码块:

  • synchronized限制static方法的时候,锁对象为这个类的class变量,相当于XXXClass.class. 例如:

    public static synchronized int setName(String name){Xxx.name = name;
    }

    等价于:

    public static int setName(String name){synchronized(Xxx.class){Xxx.name = name;}
    }

  • synchronized限制非static方法的时候,锁对象为这个类的实例(相当于this).例如:
    public synchronized int getX() {return x++;
    }

    等价于:

    public int getX() {synchronized (this) {return x;}
    }

  • synchronized限制一个对象实例的时候,如(synchronized (xlock)),锁对象为指定的这个对象实例,如xlock.

synchronized限制static方法的时候,在某一时刻,同一个虚拟机只能有一个线程正在执行这个static方法,因为锁对象是这个class的XXXClass.class实例,一个虚拟机只有一个XXXClass.class实例

如果把myThread.java文件代码改成如下:

public class myThread extends Thread {private static int count=0;private static Object o=new Object();//定义一个Object对象,用于锁
    @Overridepublic synchronized void run() {for(int i=0;i<20;i++){count+=1;System.out.println("My name is "+this.getName()+" count= "+count);            try {sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}public myThread(String arg0) {super(arg0);}
}

执行的结果:

My name is first count= 1
My name is secod count= 2
My name is secod count= 3
My name is first count= 4
My name is first count= 5
My name is secod count= 6
My name is secod count= 7
.....
.....
My name is secod count= 34
My name is first count= 35
My name is secod count= 36
My name is secod count= 37
My name is first count= 38
My name is first count= 39
My name is secod count= 40

可见是交叉执行的,那是因为synchronized限制某一个类的非static方法的时候,对这个类的某一特定实例,在某一时刻,同一个虚拟机只能有一个线程正在执行这个方法,但是可以同时执行多个实例的这个特定方法,因为锁对象不同.

转载于:https://www.cnblogs.com/zhaiqianfeng/archive/2012/08/17/4617055.html

Java 多线程初探(二) - 通讯与协调相关推荐

  1. Java多线程入门二

    Java多线程入门二 基类 package com.cv.DuoXianCheng;import lombok.extern.slf4j.Slf4j;@Slf4j public class Hero ...

  2. Java总结篇系列:Java多线程(二)

    本文承接上一篇文章<Java总结篇系列:Java多线程(一)>. 四.Java多线程的阻塞状态与线程控制 上文已经提到Java阻塞的几种具体类型.下面分别看下引起Java线程阻塞的主要方法 ...

  3. java多线程间的通讯

    什么是多线程之间的通讯? 就是多个线程在操作同一个资源,但是操作的动作不同. package com;class Printer{// 打印机public String fileName;public ...

  4. Java多线程系列(二):线程的五大状态,以及线程之间的通信与协作

    在Java面试的时候,经常会问到Java并发编程相关的多线程.线程池.线程锁.线程通信等面试必考点,比如: Java并发编程系列:Java线程池的使用方式,核心运行原理.以及注意事项 Java并发编程 ...

  5. Java多线程(二)之Atomic:原子变量与原子类

    一.何谓Atomic? Atomic一词跟原子有点关系,后者曾被人认为是最小物质的单位.计算机中的Atomic是指不能分割成若干部分的意思.如果一段代码被认为是Atomic,则表示这段代码在执行过程中 ...

  6. Java多线程学习(二)---线程创建方式

    线程创建方式 摘要: 1. 通过继承Thread类来创建并启动多线程的方式 2. 通过实现Runnable接口来创建并启动线程的方式 3. 通过实现Callable接口来创建并启动线程的方式 4. 总 ...

  7. Java多线程(二)——多线程基本特性

    目录 一.引言 二.优先级 三.睡眠sleep 四.加入线程join 五.礼让线程yield 六.守护线程daemon 七.中断线程 八.总结 一.引言 在jdk1.5之前多线程有很多基础的功能,下面 ...

  8. java多线程学习二、安全与不安全示例:12306买票和银行取钱、java内存模型、内存可见性、线程同步块和方法

    文章目录 前言 1. 什么是块,分为几种 2. 静态块与构造块的区别 一. 举例说明:并发情况下,线程不安全 1. 示例1:unsafe12306取票 2. 示例2:unsafe银行取钱 二.线程不安 ...

  9. Java多线程(二):Thread类

    Thread类的实例方法 start() start方法内部会调用方法start方法启动一个线程,该线程返回start方法,同时Java虚拟机调用native start0启动另一个线程调用run方法 ...

最新文章

  1. JAVA架构师面试题and如何成为架构师
  2. java 方法执行结束局部变量释放_JAVA-方法在执行过程中,JVM的内存分配和变化情况,栈(stack)的情况浅析...
  3. html切换选择项,HTML选择选项元素
  4. centos7下php设置用户和组,centos系统添加/删除用户和用户组的例子
  5. 关于 Node.js 参数 max-old-space-size
  6. 马云狂炸近百亿,你的借呗额度涨了吗?
  7. Java技术:为什么不推荐使用BeanUtils属性转换工具
  8. iOS开发者《用2块钱快速创建你的网站或博客》
  9. linux邮件客户端软件,适用于Linux的4款最佳电子邮件客户端 | MOS86
  10. tanh函数matlab_MATLAB模拟双曲正切函数tanh和双曲余切函数coth
  11. 用python算24点及原理详解
  12. DBLE分库分表中间件
  13. 工作那些事(二十八)项目管理模式:项目型、职能型、矩阵型
  14. 什么是变量?变量的本质是什么?变量的生命周期和作用域
  15. 区块链≠分布式账本,别再傻傻分不清
  16. 不用找了,这300家公司面试不考算法
  17. 九连环的递归实现,以及数列通项
  18. 正则表达式口诀 正则表达式学习工具
  19. Java多数据源最通俗讲解
  20. 虚拟化系列-VMware vSphere 5.1 VDP备份管理

热门文章

  1. 算法:合并两个有序链表
  2. MySQl笔记8:把good表中商品名为‘诺基亚xxxx‘的商品,改为‘HTCxxxx‘
  3. 安装NFS服务,并挂载到开发板
  4. 常考数据结构与算法-NC105 二分查找-II
  5. 史上最全,最完美的 JAVA 技术体系思维导图总结,没有之一!
  6. 汇编:call指令的应用
  7. 移动端开发 rem 单位使用问题
  8. 【前端词典】和媳妇讲代理后的意外收获
  9. 【Visual Studio】如何在VS 2012中打印变量值到输出窗口
  10. Sub-process /usr/bin/dpkg returned an error code (1)