zoukankan      html  css  js  c++  java
  • 线程Thread中的方法详解(二)

    1、start()

    • start()方法的作用讲得直白点就是通知"线程规划器",此线程可以运行了,正在等待CPU调用线程对象得run()方法,产生一个异步执行的效果。通过start()方法产生得到结论,先看下代码:
    /**
     * @author zs
     * @date 2019/9/20 10:13
     */
    public class MyTicketThread extends  Thread {
        private int ticket=5;//仅剩五张票
        public MyTicketThread(String threadName) {
            super(threadName);//调用父类的带参构造方法
        }
    
        @Override
        public void run() {
    
    
            // TODO Auto-generated method stub
            for(int i=0;i<100;i++){
                synchronized (this) {
                    if(ticket>0){
                        try {
                            Thread.sleep(300);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "卖第"
                                + (ticket--) + "张票");
                    }
                }
            }
        }
    }
    /**
    * @author zs
    * @date 2019/9/20 10:14
    */
    public class Test {
    public static void main(String[] args) {
    //4个窗口
    MyTicketThread t1=new MyTicketThread("A窗口");
    MyTicketThread t2=new MyTicketThread("B窗口");
    MyTicketThread t3=new MyTicketThread("C窗口");
    MyTicketThread t4=new MyTicketThread("D窗口");
    //启动线程
    t1.start();
    t2.start();
    t3.start();
    t4.start();
    }
    }


    运行结果:

    B窗口卖第5张票
    C窗口卖第5张票
    D窗口卖第5张票
    A窗口卖第5张票
    D窗口卖第4张票
    A窗口卖第4张票
    B窗口卖第4张票
    C窗口卖第4张票
    D窗口卖第3张票
    A窗口卖第3张票

    ...

     
    • 解释:可以看出,线程执行的先后顺序,是不确定的。

    2、currentThread()

    currentThread()方法返回的是对当前正在执行线程对象的引用

    在线程类中,有两种方式,一定要理解这两种方式的区别:

    (1)this.XXX()

    这种调用方式表示的线程是线程实例本身

    (2)Thread.currentThread.XXX()或Thread.XXX()

    上面两种写法是一样的意思。这种调用方式表示的线程是正在执行Thread.currentThread.XXX()所在代码块的线程

    下面通过看一个重要的例子,然后得出结论:

    复制代码
    public class MyThread04 extends Thread
    {
        static
        {
            System.out.println("静态块的打印:" + 
                    Thread.currentThread().getName());    
        }
        
        public MyThread04()
        {
            System.out.println("构造方法的打印:" + 
                    Thread.currentThread().getName());    
        }
        
        public void run()
        {
            System.out.println("run()方法的打印:" + 
                    Thread.currentThread().getName());
        }
    }
    复制代码
    public static void main(String[] args)
    {
        MyThread04 mt = new MyThread04();
        mt.start();
    }

    看一下运行结果:

    静态块的打印:main
    构造方法的打印:main
    run()方法的打印:Thread-0

    这个例子说明了,线程类的构造方法、静态块是被main线程调用的,而线程类的run()方法才是应用线程自己调用的。在这个例子的基础上,再深入:

    复制代码
    public class MyThread05 extends Thread
    {
        public MyThread05()
        {
            System.out.println("MyThread5----->Begin");
            System.out.println("Thread.currentThread().getName()----->" + 
                    Thread.currentThread().getName());
            System.out.println("this.getName()----->" + this.getName());
            System.out.println("MyThread5----->end");
        }
        
        public void run()
        {
            System.out.println("run----->Begin");
            System.out.println("Thread.currentThread().getName()----->" + 
                    Thread.currentThread().getName());
            System.out.println("this.getName()----->" + this.getName());
            System.out.println("run----->end");
        }
    }
    复制代码
    public static void main(String[] args)
    {
        MyThread05 mt5 = new MyThread05();
        mt5.start();
    }

    看一下运行结果:

    复制代码
    MyThread5----->Begin
    Thread.currentThread().getName()----->main
    this.getName()----->Thread-0
    MyThread5----->end
    run----->Begin
    Thread.currentThread().getName()----->Thread-0
    this.getName()----->Thread-0
    run----->end
    复制代码

    可以看出:当前执行的Thread未必就是Thread本身。从这个例子就能看出来:

    (1)执行MyThread05构造方法是main,当前线程却是Thread-0

    (2)执行run()方法的Thread-0,当前线程也是Thread-0,说明run()方法就是被线程实例去执行的

    所以,再强调一下,未必在MyThread05里调用Thread.currentThread()返回回来的线程对象的引用就是MyThread05。

    3、sleep(long millis)

    sleep(long millis)方法的作用是在指定的毫秒内让当前"正在执行的线程"休眠(暂停执行)。这个"正在执行的线程"是关键,指的是Thread.currentThread()返回的线程。根据JDK API的说法,"该线程不丢失任何监视器的所属权",简单说就是sleep代码上下文如果被加锁了,锁依然在,但是CPU资源会让出给其他线程。看一下例子:

    复制代码
    public class MyThread07 extends Thread
    {
        public void run()
        {
            try
            {
                System.out.println("run threadName = " + 
                        this.getName() + " begin");
                Thread.sleep(2000);
                System.out.println("run threadName = " + 
                        this.getName() + " end");
            } 
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }
    复制代码
    复制代码
    public static void main(String[] args)
    {
        MyThread07 mt = new MyThread07();
        System.out.println("begin = " + System.currentTimeMillis());
        mt.start();
        System.out.println("end = " + System.currentTimeMillis());
    }
    复制代码

    看一下运行结果:

    begin = 1443694780609
    end = 1443694780609
    run threadName = Thread-0 begin
    run threadName = Thread-0 end

    当然,因为打印结果是静态的,所以只能看出异步执行的效果,看不出sleep(long millis)方法执行的效果。实际上第3句打出2秒后打出第4句,这和run()方法里面的sleep(2000)是对应的

    4、yield()

    暂停当前执行的线程对象,并执行其他线程。这个暂停是会放弃CPU资源的,并且放弃CPU的时间不确定,有可能刚放弃,就获得CPU资源了,也有可能放弃好一会儿,才会被CPU执行。看一下例子:

    复制代码
    public class MyThread08 extends Thread
    {
        public void run()
        {
            long beginTime = System.currentTimeMillis();
            int count = 0;
            for (int i = 0; i < 50000000; i++)
            {
                Thread.yield();
                count = count + i + 1;
            }
            long endTime = System.currentTimeMillis();
            System.out.println("用时:" + (endTime - beginTime) + "毫秒!");
        }
    }
    复制代码
    public static void main(String[] args)
    {
        MyThread08 mt = new MyThread08();
        mt.start();
    }

    看一下运行结果:

    复制代码
    用时:3264毫秒!
    用时:3299毫秒!
    用时:3232毫秒!
    用时:3256毫秒!
    用时:3283毫秒!
    用时:3504毫秒!
    用时:3378毫秒!
    复制代码

    看到,每次执行的用时都不一样,证明了yield()方法放弃CPU的时间并不确定。

     5、注意

    1、sleep()和wait()方法的区别,三点:

    1. sleep()是Thread中的方法,线程休眠;wait()是Object中的方法,线程等待;
    2. 都导致线程的阻塞;
    3. sleep()对对象所持有的锁不释放,wait()释放所持有的锁;

    2、Java中Wait、Sleep和Yield方法的区别

    • wait()是Object的方法,用于线程间的通信,线程等待,进入阻塞状态,会释放锁;
    • sleep是Thread的静态方法,调用该方法,令当前线程休眠,进入阻塞状态,不会释放锁;
    • yield和sleep的主要是,yield方法会临时暂停当前正在执行的线程,来让有同样优先级的正在等待的线程有机会执行。如果没有正在等待的线程,或者所有正在等待的线程的优先级都比较低,那么该线程会继续运行。执行了yield方法的线程什么时候会继续运行由线程调度器来决定,不同的厂商可能有不同的行为。yield方法不保证当前的线程会暂停或者停止,但是可以保证当前线程在调用yield方法时会放弃CPU。
    如果错过太阳时你流了泪,那你也要错过群星了。
    在所有的矛盾中,要优先解决主要矛盾,其他矛盾也就迎刃而解。
    不要做个笨蛋,为失去的郁郁寡欢,聪明的人,已经找到了解决问题的办法,或正在寻找。
  • 相关阅读:
    ubuntu用mentohust连接ruijie
    vim系统剪切板
    JSP 页面中用绝对路径显示图片
    response.setContentType与 request.setCharacterEncoding 区别
    安装mysql数据库要注意的
    eclipse link方式安装插件安装不上
    Windows程序调用dll
    DP 问题
    LeetCode Repeated Substring Pattern
    LeetCode Number of Segments in a String
  • 原文地址:https://www.cnblogs.com/szrs/p/11851482.html
Copyright © 2011-2022 走看看