一、sleep的使用

 public class ThreadTest {
public static void main(String[] args) throws InterruptedException {
Object obj = new Object();
MyThread mt = new MyThread(obj);
mt.start();
MyThread mt2 = new MyThread(obj);
mt2.start();
}
private static class MyThread extends Thread{
private Object obj;
public MyThread(Object obj) {
this.obj = obj;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() +
" synchronized之前: " + System.currentTimeMillis());
synchronized(obj) {
System.out.println(Thread.currentThread().getName() +
" sleep之前: " + System.currentTimeMillis());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
" sleep之后: " + System.currentTimeMillis());
}
}
}
}

输出:

Thread-1 synchronized之前: 1546337474050
Thread-0 synchronized之前: 1546337474050
Thread-1 sleep之前: 1546337474051
Thread-1 sleep之后: 1546337476051
Thread-0 sleep之前: 1546337476051
Thread-0 sleep之后: 1546337478052

线程Thread-0和线程Thread-1监控同一个资源obj,Thread-1在sleep之后并没有释放对象锁。

好比,A和B去店里买衣服,只有一间试衣间,一把试衣间的钥匙,A先拿到试衣间钥匙(obj),进入试衣间(synchronized(obj) {...}),

并在试衣间睡了一觉(sleep(2000)),B只能等A醒来走出试衣间,才能有机会拿到钥匙并进入试衣间。

调用native方法:public static native void sleep(long millis) throws InterruptedException;

二、wait和notify的使用

 public class ThreadTest {
public static void main(String[] args) throws InterruptedException {
Object obj = new Object();
MyThread mt = new MyThread(obj);
mt.start();
MyThread2 mt2 = new MyThread2(obj);
mt2.start();
}
private static class MyThread extends Thread{
private Object obj;
public MyThread(Object obj) {
this.obj = obj;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() +
" synchronized之前: " + System.currentTimeMillis());
synchronized(obj) {
System.out.println(Thread.currentThread().getName() +
" wait之前: " + System.currentTimeMillis());
try {
obj.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
" wait之后: " + System.currentTimeMillis());
}
}
}
private static class MyThread2 extends Thread{
private Object obj;
public MyThread2(Object obj) {
this.obj = obj;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() +
" synchronized之前: " + System.currentTimeMillis());
synchronized(obj) {
System.out.println(Thread.currentThread().getName() +
" notify之前: " + System.currentTimeMillis());
obj.notify();
System.out.println(Thread.currentThread().getName() +
" notify之后: " + System.currentTimeMillis());
}
}
}
}

输出:

Thread-0 synchronized之前: 1546349737274
Thread-0 wait之前: 1546349737274
Thread-1 synchronized之前: 1546349737274
Thread-1 notify之前: 1546349737275
Thread-1 notify之后: 1546349737275
Thread-0 wait之后: 1546349737275

Thread-0在执行了obj.wait()之后,线程暂停并释放对象锁,之后,Thread-1获得对象锁,Thread-1执行obj.notify()后Thread-0苏醒,Thread-1执行完synchronized的代码块之后,Thread-0才有机会获得锁。

1、wait()让当前线程进入“等待状态”,并让当前线程释放它所持有的锁。直到其他线程调用此对象的notify()方法或notify()方法,当前线程被唤醒,进入“就绪状态”。

2、notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程。notify()是唤醒单个线程(随机唤醒),而notifyAll()是唤醒所有的线程。

3、wait(long timeout)让当前线程处于“等待(阻塞)状态”,直到其他线程调用此对象的notify()方法或notifyAll()方法,或者超过指定的时间量,当前线程被唤醒,进入“就绪状态”。

4、调用 wait()、notify()、notifyAll() 方法之前,必须获得对象锁,即,只能在同步方法中调用。

5、执行 notify() 之后,并不会立即退出让wait的线程执行,必须要先将同步块中的程序执行完,退出同步块,才会释放锁,让等待线程执行。

6、每调用一次 notify() 只能唤醒一个线程,多次调用可通知多个线程。

wait()、notify()、notifyAll()都是Object的方法。

原理:

每个对象都有个monitor,初始是0,执行完synchronized值就是1。

wait/notify需要在获得monitor的线程中才可以执行。

所以,wait/notify需要在synchronized中执行。

其中,wait又会释放掉锁,破坏掉同步。

和synchronized的关系:

synchronized代码块生成的字节码,被monitorenter和monitorexit包围,持有对象的monitor,线程执行wait/notify方法时,必须持有对象的monitor,所以,wait/notify方法在synchronized同步快中执行,就持有了对象的锁。

互斥和协同:

java语言的同步机制在底层实现上就只有两种方式:互斥和协同。

互斥:即synchronized内置锁。

协同:即内置条件队列,wait/notify/notyfiAll。

条件队列是处于等待状态的线程,等待特定条件为真。每个java对象都可以作为一个锁,同样每个java对象都可以作为一个条件队列。通过wait/notify/notifyAll来操作条件队列。

可以理解为:有一个队列,o.wait()就push进去,o.notify()就pull出来。、

要调用条件队列的任何一个方法,都必须要获得对象上的锁。

三、join的使用

 public class ThreadTest {
public static void main(String[] args) throws InterruptedException {
Object obj = new Object();
MyThread mt = new MyThread(obj);
mt.start();
//在main中调用mt.join()
mt.join();
System.out.println("main");
}
private static class MyThread extends Thread{
private Object obj;
public MyThread(Object obj) {
this.obj = obj;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() +
" synchronized之前: " + System.currentTimeMillis());
synchronized(obj) {
System.out.println(Thread.currentThread().getName() +
" sleep之前: " + System.currentTimeMillis());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
" sleep之后: " + System.currentTimeMillis());
}
}
}
}

输出:

Thread-0 synchronized之前: 1546354871560
Thread-0 sleep之前: 1546354871560
Thread-0 sleep之后: 1546354874561
main

在main中调用了线程mt的join方法(mt.join()),则线程main会等线程mt执行完毕后再恢复运行。

join()方法由wait()实现。源码:

java Thread源码分析(二)的更多相关文章

  1. java Thread源码分析

    一.使用 java 多线程 java多线程其中两种使用方式: 1.继承 Thread 类 2.实现 Runnable 接口 public class ThreadTest { public stati ...

  2. 多线程之美8一 AbstractQueuedSynchronizer源码分析<二>

    目录 AQS的源码分析 该篇主要分析AQS的ConditionObject,是AQS的内部类,实现等待通知机制. 1.条件队列 条件队列与AQS中的同步队列有所不同,结构图如下: 两者区别: 1.链表 ...

  3. Java Reference 源码分析

    @(Java)[Reference] Java Reference 源码分析 Reference对象封装了其它对象的引用,可以和普通的对象一样操作,在一定的限制条件下,支持和垃圾收集器的交互.即可以使 ...

  4. 框架-springmvc源码分析(二)

    框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...

  5. java集合源码分析(三):ArrayList

    概述 在前文:java集合源码分析(二):List与AbstractList 和 java集合源码分析(一):Collection 与 AbstractCollection 中,我们大致了解了从 Co ...

  6. java集合源码分析(六):HashMap

    概述 HashMap 是 Map 接口下一个线程不安全的,基于哈希表的实现类.由于他解决哈希冲突的方式是分离链表法,也就是拉链法,因此他的数据结构是数组+链表,在 JDK8 以后,当哈希冲突严重时,H ...

  7. Fresco 源码分析(二) Fresco客户端与服务端交互(1) 解决遗留的Q1问题

    4.2 Fresco客户端与服务端的交互(一) 解决Q1问题 从这篇博客开始,我们开始讨论客户端与服务端是如何交互的,这个交互的入口,我们从Q1问题入手(博客按照这样的问题入手,是因为当时我也是从这里 ...

  8. Java 集合源码分析(一)HashMap

    目录 Java 集合源码分析(一)HashMap 1. 概要 2. JDK 7 的 HashMap 3. JDK 1.8 的 HashMap 4. Hashtable 5. JDK 1.7 的 Con ...

  9. Tomcat源码分析二:先看看Tomcat的整体架构

    Tomcat源码分析二:先看看Tomcat的整体架构 Tomcat架构图 我们先来看一张比较经典的Tomcat架构图: 从这张图中,我们可以看出Tomcat中含有Server.Service.Conn ...

随机推荐

  1. JavaScript apply

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply The ...

  2. 安装ubuntu双系统

    今天在win7下安装ubuntu14.1双系统,别折磨了一个下午.主要是开机系统引导问题. 引导程序是位于硬盘最前面的一段程序,由于扇区大部分是引导程序,故也成引导扇区.此外包含有硬盘的分区信息,共6 ...

  3. Binary-to-text ecoding:

    binary to Text ecoding是指将二进制数据转换成可打印的符号 如果传输channel 不允许二进制数据(如email) 一般使用Base64 ASCII 标准使用128位来表示字母数 ...

  4. firewalld无法使用解决

    一.安装完Python3.6.5后无法使用firewalld解决 解决:需要把/usr/sbin/firewalld./usr/bin/firewall-cmd 的头部内容改为原来的 pyton2.7 ...

  5. Linux几个命令的升级替代品

    grep => ack, agack和ag是两个文本搜索工具,比自带的grep要好用得多.在指定目录下搜索文本时,它们不需要像grep那样指定各种命令行选项,输出结果也会包含文件名和行号,并且会 ...

  6. Java ——运算符

    本节重点思维导图 递增递减 前缀自增自减法(++a,--a): 先进行自增.减运算,再进行表达式运算 后缀自增自减法(a++,a--): 先进行表达式运算,再进行自增.减运算 例[1]: int a ...

  7. 【Python】我的第一个豆瓣短评爬虫

    写在开头 豆瓣上有着大量的影视剧的评论,所以说,要是想要实现对广大人民群众的观点的分析,对一部片子的理解,综合来看大家的评论是很有必要的.而短评作为短小精干的快速评论入口,是值得一谈的. 所以先要实现 ...

  8. Windows.etc\hosts文件

    ZC:就是将 后面的项 重定位到 前面的项 1.目录:"C:\Windows\System32\drivers\etc" 文件:"C:\Windows\System32\ ...

  9. axios入门使用

    vue项目中axios的基本使用和简单封装 axios中文文档官网 http://www.axios-js.com/docs/ 一:不封装直接使用 npm install axios 在main.js ...

  10. python 并发编程 多进程 互斥锁

    运行多进程  每个子进程的内存空间是互相隔离的 进程之间数据不能共享的 一 互斥锁 但是进程之间都是运行在一个操作系统上,进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终 ...