zoukankan      html  css  js  c++  java
  • 多线程:深入Thread.sleep

    一直都说,Threed.sleep是不会释放锁,而wait是释放锁的(对象锁),现理论上来分析一下。

    由于CPU分配的每个线程的时间片极为短暂(一般为几十毫秒),所以,CPU通过不停地切换线程执行,这样就给程序员一种错觉,以为多个线程是在同时执行。sleep就是正在执行的线程主动让出CPU,CPU去执行其他线程,在sleep指定的时间过后,CPU才会回到这个线程上继续往下执行,如果当前线程进入了同步锁,sleep方法并不会释放锁,即使当前线程使用sleep方法让出了CPU,但其他被同步锁挡住了的线程也无法得到执行。

    package thread.concurrent;
    
    public class DeepenSleep implements Runnable {
         private int number = 10;
    
         public void firstMethod() throws Exception {
                synchronized (this) {
                    System. out.println("in first method");
                     number += 100;
                    System. out.println("+100=" + number);
               }
         }
    
         public void secondMethod() throws Exception {
                synchronized (this) {
                    System. out.println("in second method, prepare sleep");
                     /**
                     * (休息2S,阻塞线程) 以验证当前线程对象的机锁被占用时, 是否被可以访问其他同步代码块
                     */
                    Thread. sleep(2000);
                    System. out.println("wake up!!");
                     // this.wait(2000);
                     number *= 200;
                    System. out.println("*200=" + number);
               }
         }
    
         @Override
         public void run() {
                try {
                    System. out.println("run thread...");
                    firstMethod();
               } catch (Exception e) {
                    e.printStackTrace();
               }
         }
    
         public static void main(String[] args) throws Exception {
               DeepenSleep dt = new DeepenSleep();
               Thread thread = new Thread(dt);
               thread.start();
               System. out.println("prepare run second method");
               dt.secondMethod();
         }
    }

    输出如下:

    执行结果

    分析:主线程启动起来,因为创建线程等的资源消耗,所以主线程会先执行 dt.secondMethod(),因此会先输出prepare run second method,其后执行secondMehtod方法(注意该方法是要先闹到锁对象),而该方法直接将线程睡眠2s(注意此处对象锁DeepenSleep的实例对象并没有释放),然后执行线程dt的run方法,该方刚发执行dt的firstMethod,然而,该方法也是需要获取锁对象的,而此时他没先不能获取到,因为secondMehtod没有释放锁(准确点讲,主线程没有释放锁);然后等了2s,主线程睡眠时间已过,他warkup之后,因为还拥有锁,因此直接run secondMethod的剩下的方法,先输出”wake up”,然后执行 number*200,执行完,主线程释放掉锁,而dt线程拿到锁,执行run方法,拿到锁,执行run方法的synchronized的剩余方法:先输出”in first method”,然后执行加100的操作。

    我们来变一下将firstMethod的同步去掉,看输出是什么样子

    package thread.concurrent;
    
    public class DeepenSleep implements Runnable {
         private int number = 10;
    
         public void firstMethod() throws Exception {
    //         synchronized (this) {
                    System. out.println( "in first method");
                     number += 100;
                    System. out.println( "+100=" + number);
    //         }
         }
    
         public void secondMethod() throws Exception {
                synchronized ( this) {
                    System. out.println( "in second method, prepare sleep");
                     /**
                     * (休息2S,阻塞线程) 以验证当前线程对象的机锁被占用时, 是否被可以访问其他同步代码块
                     */
                    Thread. sleep(2000);
                    System. out.println( "wake up!!");
                     // this.wait(2000);
                     number *= 200;
                    System. out.println( "*200=" + number);
               }
         }
    
         @Override
         public void run() {
                try {
                    System. out.println( "run thread...");
                    firstMethod();
               } catch (Exception e) {
                    e.printStackTrace();
               }
         }
    
         public static void main(String[] args) throws Exception {
               DeepenSleep dt = new DeepenSleep();
               Thread thread = new Thread(dt);
               thread.start();
               System. out.println( "prepare run second method");
               dt.secondMethod();
         }
    }

    输出如下:

    执行结果

    分析:不同点在于,主线程睡眠之后,没有释放锁,dt线程执行firstMethod并不需要锁,因此先run firstMethod中的逻辑,先加100,然今,主线程睡醒之后,再执行剩下的逻辑,乘以200。

    Thread.sleep(1000),1000ms后是否立即执行?

    不一定,在未来的1000毫秒内,线程不想再参与到CPU竞争。那么1000毫秒过去之后,这时候也许另外一个线程正在使用CPU,那么这时候操作系统是不会重新分配CPU的,直到那个线程挂起或结束;况且,即使这个时候恰巧轮到操作系统进行CPU 分配,那么当前线程也不一定就是总优先级最高的那个,CPU还是可能被其他线程抢占去。

    Thread.sleep(0),是否有用?

    boss:“给你睡0小时”。
    
    coder:“你TM逗我啊”。
    

    休眠0ms,这样的休眠有何意义?Thread.Sleep(0)的作用,就是“触发操作系统立刻重新进行一次CPU竞争,重新计算优先级”。竞争的结果也许是当前线程仍然获得CPU控制权,也许会换成别的线程获得CPU控制权。这也是我们在大循环里面经常会写一句Thread.sleep(0) ,因为这样就给了其他线程比如Paint线程获得CPU控制权的权力,这样界面就不会假死在那里。

  • 相关阅读:
    Centos7 安装Postgres11(更改数据目录)
    将trj保存成.gpx文件方便进行地图匹配(来自徐博士的支援)
    将北京路网OSM文件导入到PostgreSQL + PostGIS 中,并利用osm2pgrouting工具+osmosis工具构建路网Graph拓扑结构
    SQL-时间-UTC-时间戳-日期-年查询在PG+PostGIS
    地理坐标系4326--投影坐标系3857/2436
    基于postgis时空查询-记录而已
    Java 接口
    单例模式
    weblogic启动一闪而过
    oracle存储过程中is和as区别
  • 原文地址:https://www.cnblogs.com/dengyungao/p/7524738.html
Copyright © 2011-2022 走看看