java Thread源码分析(二)

一、sleep的使用

 1 public class ThreadTest {
 2     public static void main(String[] args) throws InterruptedException {
 3         Object obj = new Object();
 4         MyThread mt = new MyThread(obj);
 5         mt.start();
 6         MyThread mt2 = new MyThread(obj);
 7         mt2.start();
 8     }
 9     private static class MyThread extends Thread{
10         private Object obj;
11         public MyThread(Object obj) {
12             this.obj = obj;
13         }
14         @Override
15         public void run() {
16             System.out.println(Thread.currentThread().getName() +
17                     " synchronized之前: " + System.currentTimeMillis());
18             synchronized(obj) {
19                 System.out.println(Thread.currentThread().getName() +
20                         " sleep之前: " + System.currentTimeMillis());
21                 try {
22                     Thread.sleep(2000);
23                 } catch (InterruptedException e) {
24                     e.printStackTrace();
25                 }
26                 System.out.println(Thread.currentThread().getName() +
27                         " sleep之后: " + System.currentTimeMillis());
28             }
29         }
30     }
31 }

输出:

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的使用

 1 public class ThreadTest {
 2     public static void main(String[] args) throws InterruptedException {
 3         Object obj = new Object();
 4         MyThread mt = new MyThread(obj);
 5         mt.start();
 6         MyThread2 mt2 = new MyThread2(obj);
 7         mt2.start();
 8     }
 9     private static class MyThread extends Thread{
10         private Object obj;
11         public MyThread(Object obj) {
12             this.obj = obj;
13         }
14         @Override
15         public void run() {
16             System.out.println(Thread.currentThread().getName() +
17                     " synchronized之前: " + System.currentTimeMillis());
18             synchronized(obj) {
19                 System.out.println(Thread.currentThread().getName() +
20                         " wait之前: " + System.currentTimeMillis());
21                 try {
22                     obj.wait();
23                 } catch (InterruptedException e) {
24                     // TODO Auto-generated catch block
25                     e.printStackTrace();
26                 }
27                 System.out.println(Thread.currentThread().getName() +
28                         " wait之后: " + System.currentTimeMillis());
29             }
30         }
31     }
32     private static class MyThread2 extends Thread{
33         private Object obj;
34         public MyThread2(Object obj) {
35             this.obj = obj;
36         }
37         @Override
38         public void run() {
39             System.out.println(Thread.currentThread().getName() +
40                     " synchronized之前: " + System.currentTimeMillis());
41             synchronized(obj) {
42                 System.out.println(Thread.currentThread().getName() +
43                         " notify之前: " + System.currentTimeMillis());
44                 obj.notify();
45                 System.out.println(Thread.currentThread().getName() +
46                         " notify之后: " + System.currentTimeMillis());
47             }
48         }
49     }
50 }

输出:

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的使用

 1 public class ThreadTest {
 2     public static void main(String[] args) throws InterruptedException {
 3         Object obj = new Object();
 4         MyThread mt = new MyThread(obj);
 5         mt.start();
 6         //在main中调用mt.join()
 7         mt.join();
 8         System.out.println("main");
 9     }
10     private static class MyThread extends Thread{
11         private Object obj;
12         public MyThread(Object obj) {
13             this.obj = obj;
14         }
15         @Override
16         public void run() {
17             System.out.println(Thread.currentThread().getName() +
18                     " synchronized之前: " + System.currentTimeMillis());
19             synchronized(obj) {
20                 System.out.println(Thread.currentThread().getName() +
21                         " sleep之前: " + System.currentTimeMillis());
22                 try {
23                     Thread.sleep(3000);
24                 } catch (InterruptedException e) {
25                     // TODO Auto-generated catch block
26                     e.printStackTrace();
27                 }
28                 System.out.println(Thread.currentThread().getName() +
29                         " sleep之后: " + System.currentTimeMillis());
30             }
31         }
32     }
33 }

输出:

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

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

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

原文地址:https://www.cnblogs.com/natian-ws/p/10211321.html

时间: 2024-10-10 05:39:48

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

JAVA Collection 源码分析(二)之SubList

昨天我们分析了ArrayList的源码,我们可以看到,在其中还有一个类,名为SubList,其继承了AbstractList. // AbstractList类型的引用,所有继承了AbstractList都可以传进来 private final AbstractList<E> parent; // 这个是其实就是parent的偏移量,从parent中的第几个元素开始的 private final int parentOffset; private final int offset; int s

Java Thread源码分析

1.Runnable接口源码: 1 public interface Runnable { 2 public abstract void run(); 3 } 2.Thread类与Runnable接口的继承关系 1 public class Thread implements Runnable{ 2 3 } Runnable接口仅有一个run()方法,Thread类实现了Runnable接口,所以,Thread类也实现了Runnable接口. 3.构造函数 1 public Thread() {

netty 源码分析二

以服务端启动,接收客户端连接整个过程为例分析, 简略分为 五个过程: 1.NioServerSocketChannel 管道生成, 2.NioServerSocketChannel 管道完成初始化, 3.NioServerSocketChannel注册至Selector选择器, 4.NioServerSocketChannel管道绑定到指定端口,启动服务 5.NioServerSocketChannel接受客户端的连接,进行相应IO操作 Ps:netty内部过程远比这复杂,简略记录下方便以后回忆

[Android]Volley源码分析(二)Cache

Cache作为Volley最为核心的一部分,Volley花了重彩来实现它.本章我们顺着Volley的源码思路往下,来看下Volley对Cache的处理逻辑. 我们回想一下昨天的简单代码,我们的入口是从构造一个Request队列开始的,而我们并不直接调用new来构造,而是将控制权反转给Volley这个静态工厂来构造. com.android.volley.toolbox.Volley: public static RequestQueue newRequestQueue(Context conte

baksmali和smali源码分析(二)

这一节,主要介绍一下 baksmali代码的框架. 我们经常在反编译android apk包的时候使用apktool这个工具,其实本身这个工具里面对于dex文件解析和重新生成就是使用的baksmali 和smali这两个jar包其中 baksmali是将 dex文件转换成便于阅读的smali文件的,具体使用命令如下:java -jar baksmali.jar classes.dex -o myout其中myout是输出的文件夹 而smali是将smali文件重新生成回 dex文件的具体使用的命

JAVA Collection 源码分析(一)之ArrayList

到今天为止,差不多已经工作一年了,一直在做的是javaweb开发,一直用的是ssh(sh)别人写好的框架,总感觉自己现在高不成低不就的,所以就像看看java的源码,顺便学习一下大牛的思想和架构,read and write一直是提高自己编程水平的不二法门,写博客只是记录自己的学习历程,方便回顾,写的不好的地方,请多多包含,不喜勿喷,好了废话少说,现在让我们开始我们的历程把,Let's go!!!!!!!! 想看源码无从下手,不知道有没有跟我一样感觉的人们,今天用Intellij发现了可以找出类与

哇!板球 源码分析二

游戏主页面布局 创建屏下Score标签 pLabel = CCLabelTTF::create("Score", "Arial", TITLE_FONT_SIZE); //分数标签 //设置标签字体的颜色 pLabel->setColor (ccc3(0, 0, 0)); //设置文本标签的位置 pLabel->setPosition ( ccp ( SCORE_X, //X坐标 SCORE_Y //Y坐标 ) ); //将文本标签添加到布景中 this

【梦幻连连连】源码分析(二)

转载请注明出处:http://blog.csdn.net/oyangyufu/article/details/24736711 GameLayer场景界面效果: 源码分析: GameLayer场景初始化,主要是初始化加载界面及背景音乐 bool GameLayer::init() { float dt=0.0f; if ( !CCLayerColor::initWithColor(ccc4(255, 255, 255, 255))) { return false; } this->initLoa

[Android]Fragment源码分析(二) 状态

我们上一讲,抛出来一个问题,就是当Activity的onCreateView的时候,是如何构造Fragment中的View参数.要回答这个问题我们先要了解Fragment的状态,这是Fragment管理中非常重要的一环.我们先来看一下FragmentActivity提供的一些核心回调: @Override protected void onCreate(Bundle savedInstanceState) { mFragments.attachActivity(this, mContainer,