• 003-多线程-基础-其他【命名和取得、休眠、优先级、线程状态、线程中断】


    一、线程命名和取得

      线程的所有操作方法几乎都在Thread类中定义好了

      从本质上上来讲,多线程的运行状态并不是固定的,唯一的区别就在于线程的名称上。

      起名:尽可能避免重名,或者避免修改名称。

      在thread类中提供如下方法:

        构造方法:public Thread(Runnable target, String name)

        设置名字:public final synchronized void setName(String name)

        取得名字:public final String getName()

      既然线程本身是不缺定的状态,所以如果要取得线程名字的话,那么唯一能做的就是取得当前线程的名字。

      所以在Thread类中有提供如下方法:

        public static native Thread currentThread();

    示例1:

    class MyThread6 implements Runnable {
        @Override
        public void run() {// 主方法
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + ",i:" + i);
            }
        }
    }
    View Code

    main方法

            MyThread6 myThread6 = new MyThread6();
            new Thread(myThread6, "线程A").start();
            new Thread(myThread6).start();
            new Thread(myThread6).start();

    如果在设置线程对象时没有设置具体名字,那么就采用一个默认的名字进行定义。

    示例2

    class MyThread7 implements Runnable {
        @Override
        public void run() {// 主方法
            System.out.println("MyThread7线程类:" + Thread.currentThread().getName());
        }
    }

    main方法

            MyThread7 myThread7 = new MyThread7();
            new Thread(myThread7, "线程A").start();
            myThread7.run();

    输出
      MyThread7线程类:线程A【new Thread(myThread7, "线程A").start();】
      MyThread7线程类:main【myThread7.run();】

    结论  

      线程依附于进程,那么进程在哪里?

      每当使用java命令在JVM上解释一个程序执行的时候,那么都会默认的启动一个JVM的进程,而主方法只是这进程中的一个线程,所以整个程序一直都泡在线程的运行机制上

      每一个JVM至少会启动两个线程,主线程、GC线程

    二、休眠

    如果想让某些线程延缓执行,那么就可以使用休眠的方式来进行处理,在Thread类里面提供如下休眠操作 。

    休眠方法:public static native void sleep(long millis) throws InterruptedException;

    InterruptedException:如果休眠时间没到就停止休眠了,那么就会产生中断异常

    示例代码1:

    class MyThread8 implements Runnable {
        @Override
        public void run() {// 主方法
            for (int i = 0; i < 100; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ",i=" + i);
            }
        }
    }
    View Code

    main方法

            MyThread8 mt = new MyThread8();
            new Thread(mt, "线程A").start();
            new Thread(mt, "线程B").start();
            new Thread(mt, "线程C").start();

    输出
      线程C,i=0
      线程A,i=0
      线程B,i=0
      线程A,i=1
      线程B,i=1
      线程C,i=1

    结论:以上代码执行中感觉像是所有的线程对象都同时休眠了,但严格来讲不是同时,是有先后顺序的,只不过顺序小一点而已。

    示例2
    main方法

            MyThread8 mt = new MyThread8();
            Thread thread = new Thread(mt, "线程A");
            thread.start();
            Thread.sleep(3000);
            thread.interrupt();

    结论:要想中断必须在其他线程操作。

    三、优先级

    从理论上来讲优先级越高的线程越有可能先执行。而在Thread类里面定义有以下的优先级操作方法。

    设置优先级:public final void setPriority(int newPriority)

    对于优先级一共定义三种:

      最低优先级:public final static int MIN_PRIORITY = 1;

      中等优先级:public final static int NORM_PRIORITY = 5;

      最高优先级:public final static int MAX_PRIORITY = 10;

      取得优先级:public final int getPriority()

    示例1,观察优先级

    class MyThread8 implements Runnable {
        @Override
        public void run() {// 主方法
            for (int i = 0; i < 100; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ",i=" + i);
            }
        }
    }
    View Code

    main 方法

            MyThread8 mt = new MyThread8();
            Thread threadA = new Thread(mt, "线程A");    
            Thread threadB = new Thread(mt, "线程B");    
            Thread threadC = new Thread(mt, "线程C");    
            threadA.setPriority(Thread.MAX_PRIORITY);
            threadB.setPriority(Thread.MIN_PRIORITY);
            threadC.setPriority(Thread.MIN_PRIORITY);
            threadA.start();
            threadB.start();
            threadC.start();
    View Code

    理论上A最先

    示例2、查看当前线程优先级

    System.out.println(Thread.currentThread().getPriority());

    结论:

    1.线程要有名称,Thread.currentThread()取得当前线程;
    2.线程休眠是有先后顺序的;
    3.理论上线程的优先级越高,越先执行

    四、深入理解线程状态

      利用JDK提供的jstack工具,查看下thread dump文件中线程的状态。NEW、RUNNABLE、TERMINATED这3个状态很容易理解,主要说明其它3种状态。

    1、显示BLOCKED状态

    public class BlockedState {
        private static Object object = new Object();
    
        public static void main(String[] args) {
            Runnable task = new Runnable() {
                @Override
                public void run() {
                    synchronized (object) {
                        long begin = System.currentTimeMillis();
    
                        long end = System.currentTimeMillis();
    
                        // 让线程运行5分钟,会一直持有object的监视器
                        while ((end - begin) <= 5 * 60 * 1000) {
    
                        }
                    }
                }
            };
    
            new Thread(task, "t1").start();
            new Thread(task, "t2").start();
        }
    }
    View Code

    先获取object的线程会执行5分钟,这5分钟内会一直持有object的监视器,另一个线程无法执行处在BLOCKED状态

    通过thread dump可以看到:t2线程确实处在BLOCKED (on object monitor)。waiting for monitor entry 等待进入synchronized保护的区域。

    2、显示WAITING状态 

    public class WaitingState {
        private static Object object = new Object();
    
        public static void main(String[] args) {
            Runnable task = new Runnable() {
                @Override
                public void run() {
                    synchronized (object) {
                        long begin = System.currentTimeMillis();
                        long end = System.currentTimeMillis();
    
                        // 让线程运行5分钟,会一直持有object的监视器
                        while ((end - begin) <= 5 * 60 * 1000) {
                            try {
                                // 进入等待的同时,会进入释放监视器
                                object.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            };
    
            new Thread(task, "t1").start();
            new Thread(task, "t2").start();
        }
    }
    View Code

    可以发现t1和t2都处在WAITING (on object monitor),进入等待状态的原因是调用了in Object.wait()。通过J.U.C包下的锁和条件队列,也是这个效果,大家可以自己实践下。

    3、显示TIMED_WAITING状态

    public class TimedWaitingState {
        // java的显示锁,类似java对象内置的监视器
        private static Lock lock = new ReentrantLock();
        // 锁关联的条件队列(类似于object.wait)
        private static Condition condition = lock.newCondition();
    
        public static void main(String[] args) {
            Runnable task = new Runnable() {
                @Override
                public void run() {
                    // 加锁,进入临界区
                    lock.lock();
                    try {
                        condition.await(5, TimeUnit.MINUTES);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 解锁,退出临界区
                    lock.unlock();
                }
            };
    
            new Thread(task, "t1").start();
            new Thread(task, "t2").start();
        }
    }
    View Code

    可以看到t1和t2线程都处在java.lang.Thread.State: TIMED_WAITING (parking),这个parking代表是调用的JUC下的工具类,而不是java默认的监视器。

    五、如何使用interupt方法中断线程 

     代码:

    public class GeneralInterrupt extends Object implements Runnable {
        public void run() {
            try {
                System.out.println("in run() - about to work2()");
                work2();
                System.out.println("in run() - back from  work2()");
            } catch (InterruptedException x) {
                System.out.println("in run() -  interrupted in work2()");
                return;
            }
            System.out.println("in run() - doing stuff after nap");
            System.out.println("in run() - leaving normally");
        }
    
        public void work2() throws InterruptedException {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("C isInterrupted()=" + Thread.currentThread().isInterrupted());
                    Thread.sleep(2000);
                    System.out.println("D isInterrupted()=" + Thread.currentThread().isInterrupted());
                }
            }
        }
    
        public void work() throws InterruptedException {
            while (true) {
                for (int i = 0; i < 100000; i++) {
                    int j = i * 2;
                }
                System.out.println("A isInterrupted()=" + Thread.currentThread().isInterrupted());
                if (Thread.interrupted()) {
                    System.out.println("B isInterrupted()=" + Thread.currentThread().isInterrupted());
                    throw new InterruptedException();
                }
            }
        }
    
        public static void main(String[] args) {
          GeneralInterrupt si = new GeneralInterrupt();
          Thread t = new Thread(si);
          t.start();
          try {
             Thread.sleep(2000);
          }
          catch (InterruptedException x) {
          }
          System.out.println("in main() - interrupting other thread");
          t.interrupt();
          System.out.println("in main() - leaving");
       }
    }
    View Code

    执行结果
      in run() - about to work2()
      in main() - interrupting other thread
      in main() - leaving
      C isInterrupted()=true
      in run() - interrupted in work2()

  • 相关阅读:
    ACM-ICPC 2018 徐州赛区网络预赛 Morgana Net
    ACM-ICPC 2018 焦作赛区网络预赛 E. Jiu Yuan Wants to Eat ,树链抛分+线段树
    ACM-ICPC 2018 焦作赛区网络预赛 Poor God Water 矩阵快速幂
    ACM-ICPC 2018 南京赛区网络预赛 E AC Challenge 状压dp
    codeforces 776 D The Door Problem
    codeforces 765 E Tree Folding
    codeforces 765 D Artsem and Saunders
    P2764 最小路径覆盖问题
    SPOJ Count on a tree 主席树+lca
    BZOJ 1066 蜥蜴
  • 原文地址:https://www.cnblogs.com/bjlhx/p/7589162.html
Copyright © 2020-2023  润新知