1,Monitor监视器与syncrhoized实现原理

1.1:Monitor

Monitor是一个同步工具,相当于操作系统中的互斥量(mutex),即值为1的信号量。

它内置与每一个Object对象中,相当于一个许可证。拿到许可证即可以进行操作,没有拿到则需要阻塞等待。

1.2:syncrhoized实现原理

syncrhoized又叫做内置锁,为什么呢?因为使用syncrhoized加锁的同步代码块在字节码引擎中执行时,其实是通过锁对象的monitor的取用与释放来实现的。由上面我们直到Monitor是内置于任何一个对象中的,syncrhoized利用monitor来实现加锁解锁,故syncrhoized又叫做内置锁。

现在我们知道为什么用syncrhoized(lock)来加锁时,锁对象可以是任意对象了:

1:syncrhoized(lock)加锁时,用到的其实只是lock对象内置的monitor而已;

2:一个对象的monitor是唯一的,相当于一个唯一的许可证。拿到许可证的线程才可以执行,执行完后释放对象的monitor才可以被其他线程获取。

我们来讲解一下syncrhoized加锁的同步块的执行过程:

现在假设有代码块:

      syncrhoized(Object lock){

同步代码...;

}

它在字节码文件中被编译为:

      monitorenter;//获取monitor许可证,进入同步块

同步代码...

monitorexit;//离开同步块后,释放monitor许可证

2,线程间的同步协作与通信协作

2.1:线程的状态以及变化图

Java中线程中状态可分为五种:New(新建状态),Runnable(就绪状态),Running(运行状态),Blocked(阻塞状态),Dead(死亡状态)。

  New:新建状态,当线程创建完成时为新建状态,即new Thread(...),还没有调用start方法时,线程处于新建状态。

  Runnable:就绪状态,当调用线程的的start方法后,线程进入就绪状态,等待CPU资源。处于就绪状态的线程由Java运行时系统的线程调度程序(thread scheduler)来调度。

  Running:运行状态,就绪状态的线程获取到CPU执行权以后进入运行状态,开始执行run方法。

  Blocked:阻塞状态,线程没有执行完,由于某种原因(如,I/O操作等)让出CPU执行权,自身进入阻塞状态。

  Dead:死亡状态,线程执行完成或者执行过程中出现异常,线程就会进入死亡状态。

2.2 线程间的同步协作

由syncrhoized同步锁、ReentrantLock(可重入锁)、ReadWriteLock(读写锁)等待同步机制,实现线程之间的同步。

说明:

1)syncrhoized也是可重入锁,基本用法

syncrhoized(Object lock){
需要同步的代码...;
}

2)ReentrantLock类(不是关键字)可以实现syncrhoized同样的效果并且有扩展功能

Lock lock = new ReentranLock();
lock.lock();
  需要同步的代码;
lock.unlock();

3)ReentrantReadWriteLock类有两个锁,读相关的锁(也叫共享锁),写相关的锁(也叫排他锁)。

ReentranReadWriteLock lock = new ReentranReadWriteLock();

lock.readLock().lock();
  需要读锁同步的代码;
lock.readLock().unlock(); lock.writeLock().lock();
  需要写锁同步的代码;
lock.writeLock().unlock();

线程获得锁则进入就绪态,等待CPU调度进入运行态;

线程申请被占用的锁,则进入阻塞态,让出CPU使用权。直到获得该锁后,重新进入就绪态,等待CPU调度进入运行态。

2.3 线程间的通信协作

在获得锁而执行的线程执行时,执行到某处时需要申请同一把锁的其他线程先执行,此时就需要让出同步锁以及CPU(进入阻塞态),让其他线程先获取同步锁以及CPU而执行。直到其他线程执行完并释放同步锁后通知它唤醒(就绪态),才接着申请同步锁以及CPU而继续执行下去(运行态)。

 这个线程之间 让出资源、挂起、唤醒 就是通过线程的通信来实现的。

两种方式:

1)syncrhoized加锁的线程的wait()/notify()/notifyAll()

2)ReentrantLock类加锁的线程的Condition类调用await()/signal()/signalAll()

Object类中的wait()/notify()/notifyAll()方法依次与Condition类中的await()/signal()/signalAll()一一对应

2.4  线程自身的动作

1) 线程自身可以通过调用 sleep() 方法进入阻塞态,暂时让出CPU资源(但是不释放锁),休眠时间过后自动恢复就绪态等待CPU调度执行;

2)线程自身可以通过调用 yield() 方法由运行态变为就绪态;这个过程称为“让步”,即正在运行的线程让出CPU给就绪态中的线程先执行一下,自己则回到就绪态中等待CPU再次调度自己执行;

3)线程可以在自身执行过程中,通过其他线程对象.join() 方法把已经启动的其他线程先执行完 ,再继续执行自身的余下操作。可以通过这个方法来实现线程之间顺序执行。

join()方法解释:

为什么要使用join:

package joinTest1;

public class MyThread extends Thread {

    @Override
public void run() {
try {
int secondValue = (int) (Math.random() * 10000);
System.out.println(secondValue);
Thread.sleep(secondValue);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} }
package joinTest1;

public class Test {

    public static void main(String[] args) {

        MyThread threadTest = new MyThread();
threadTest.start(); // Thread.sleep(?)
System.out.println("我想当threadTest对象执行完毕后我再执行");
System.out.println("但上面代码中的sleep()中的值应该写多少呢?");
System.out.println("答案是:根据不能确定:)");
} }

运行结果:

问题就是,我们当前线程想在某个线程(其实就是当前线程的子线程)执行完成后执行,要等多长时间,其实还有一个问题是,join内部是wait实现的会释放锁,而sleep不会释放锁。

package joinTest2;

public class MyThread extends Thread {

    @Override
public void run() {
try {
int secondValue = (int) (Math.random() * 10000);
System.out.println(secondValue);
Thread.sleep(secondValue);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} }
package joinTest2;

public class Test {

    public static void main(String[] args) {
try {
MyThread threadTest = new MyThread();
threadTest.start(); //启动子线程
threadTest.join(); //当时间片又来到当前线程(父线程)时,运行了子线程类的join方法,把当前线程(父线程)无限期阻塞,直到子线程销毁再执行父线程余下的代码。 System.out.println("我想当threadTest对象执行完毕后我再执行,我做到了");
} catch (InterruptedException e) {
e.printStackTrace();
}
} }

运行结果

方法join具有使线程排队运行的作用。

《Java多线程编程核心技术》

http://www.cnblogs.com/ygj0930/p/6561589.html

https://www.cnblogs.com/ygj0930/p/6561667.html

Java并发之线程间的同步协作与通信协作的更多相关文章

  1. java并发之线程间通信协作

    在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者模型:当队列满时,生产者需要等待队列有空间才能继续往里面放入商品,而在等待的期间内,生产者必须释放对临界 ...

  2. Java并发之线程间的协作

    上篇文章我们介绍了synchronized关键字,使用它可以有效的解决我们多线程所带来的一些常见问题.例如:竞态条件,内存可见性等.并且,我们也说明了该关键字主要是一个加锁和释放锁的集成,所有为能获得 ...

  3. java并发之线程间通信

    1.volatile 关键字 java 支持多个线程同时访问一个对象或对象的成员变量,而每个线程拥有这个变量的拷贝,虽然对象或成员变量分配的内存在共享内存,但每个执行的线程可以拥有一份拷贝,可以提高程 ...

  4. java多线程与线程间通信

    转自(http://blog.csdn.net/jerrying0203/article/details/45563947) 本文学习并总结java多线程与线程间通信的原理和方法,内容涉及java线程 ...

  5. vc++高级班之多线程篇[7]---线程间的同步机制②

    //示例代码: CStringArray g_ArrString; UINT __cdecl ThreadProc(LPVOID lpParameter) {  int startIdx = (int ...

  6. vc++高级班之多线程篇[6]---线程间的同步机制①

    ①.线程同步的必要性:   int g_Num = 0; UINT __cdecl ThreadProc(LPVOID lpParameter) {  for (int idx = 0; idx &l ...

  7. java并发编程 线程间协作

    线程间协作 1. 等待和通知 等待和通知的标准形式 等待方: 获取对象锁 循环中判断条件是否满足,不调用wait()方法 条件满足执行业务逻辑 通知方: 获取对象所 改变条件 通知所有等待在对象的线程 ...

  8. Java中详述线程间协作

    线程协作 首先引入一段代码: package 线程间数据共享; import java.util.Date; public class Watch { private static String ti ...

  9. Java核心知识点学习----多线程并发之线程间的通信,notify,wait

    1.需求: 子线程循环10次,主线程循环100次,这样间隔循环50次. 2.实现: package com.amos.concurrent; /** * @ClassName: ThreadSynch ...

随机推荐

  1. JSON以及Java转换JSON的方法(前后端经常使用处理方法)

    本文主要讲述例如以下几个内容: 1.JSON定义以及JSON的特性 2.怎样在JavaScript中解释JSON格式数据 3.怎样在Java代码中使用JSON(讲对象转换成JSON对象以及解释JSON ...

  2. Lightoj 1112 - Curious Robin Hood 【单点改动 + 单点、 区间查询】【树状数组 水题】

    1112 - Curious Robin Hood PDF (English) Statistics Forum Time Limit: 1 second(s) Memory Limit: 64 MB ...

  3. Android最佳实践之性能 - 多线程

    在单独线程执行代码 參考地址:http://developer.android.com/training/multiple-threads/define-runnable.html Runnable对 ...

  4. 【cocos2d-x 3.7 飞机大战】 决战南海I (十二) 游戏结束场景

    游戏结束的时候,要显示分数.还要可以选择是返回主场景还是退出游戏 // 退出游戏 void menuCloseCallback(cocos2d::Ref* pSender); // 返回主界面 voi ...

  5. luogu1447 能量采集

    题目大意 给出m,n,对于每一个整数x∈[1,m],y∈[1,n]都有一点(x,y).处理每个点所需要的能量为2*k+1,k为该点到原点经过的点的数量(不包括该点本身).求处理所有点所需要的能量和. ...

  6. 10.TCPIP监听器

    给它做代理之后你这个端口是什么? 做一个代理. Local monitoring port:本地的监听端口.你要给谁做代理,那么给它做代理之后,你这个代理的端口是什么? 现在要给百度做一个代理. 能看 ...

  7. js slider

      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.or ...

  8. POJ 2337 欧拉回路

    题意: 如果给出的单词能够首尾相接,请按字典序输出单词,中间要加'.' 否则输出三个"*". 思路: 欧拉回路 记得按字典序排序哦~ 加边的时候要倒着加.(邻接表遍历的时候是反着的 ...

  9. 利用Axis2默认口令安全漏洞入侵WebService网站

    近期,在黑吧安全网上关注了几则利用Axis2默认口令进行渗透测试的案例,大家的渗透思路基本一致,利用的技术工具也大致相同,我在总结这几则案例的基础之上进行了技术思路的拓展.黑吧安全网Axis2默认口令 ...

  10. 深入jar包:从jar包中读取资源文件

    我们常常在代码中读取一些资源文件(比如图片,音乐,文本等等).在单独运行的时候这些简单的处理当然不会有问题.但是,如果我们把代码打成一个jar包以后,即使将资源文件一并打包,这些东西也找不出来了.看看 ...