zoukankan      html  css  js  c++  java
  • java从基础知识(十)java多线程(上)

      线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪阻塞运行三种基本状态。就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;运行状态是指线程占有处理机正在运行;阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。

      这一节介绍线程的启动方式及Thread类。

    一、线程的启动方式

    1、通过Thread类启动

    public class ThreadTest extends Thread {
    
        private String name;
    
        public ThreadTest(String name) {
            this.name = name;
        }
    
        @Override
        public void run() {
            for(int i = 0; i < 100; i++)
            System.out.println(name + " thread : " + i);
        }
    
        public static void main(String[] args) {
            ThreadTest tt1 = new ThreadTest("tt1");
            tt1.start();//使该线程开始执行;Java 虚拟机调用该线程的 run 方法
            ThreadTest tt2 = new ThreadTest("tt2");
            tt2.start();
        }
    }

      注意:线程是通过start的方法启动的,run方法是用来实现逻辑的。

    2、通过Runnable接口启动

    public class RunnableTest implements Runnable {
    
        private String name;
    
        public RunnableTest(String name) {
            this.name = name;
        }
    
        public void run() {
            for (int i = 0; i < 100; i++) {
                System.out.println(name + " runnabel : " + i);
            }
        }
    
        public static void main(String[] args) {
            RunnableTest rt1 = new RunnableTest("rt1");
            Thread t1 = new Thread(rt1);
            t1.start();
            RunnableTest rt2 = new RunnableTest("rt2");
            Thread t2 = new Thread(rt2);
            t2.start();
        }
    }

    3、使用ExecutorService、Callable、Future实现有返回结果的多线程

    public class ExcuteTest {
    
        public static void main(String[] args) {
            System.out.println("----程序开始运行----");
    
            int taskSize = 5;
            // 创建一个线程池
            ExecutorService pool = Executors.newFixedThreadPool(taskSize);
            // 创建多个有返回值的任务
            List<Future> list = new ArrayList<Future>();
            for (int i = 1; i < taskSize + 1; i++) {
                Callable c = new MyCallable(i + " ");
                // 执行任务并获取Future对象
                Future f = pool.submit(c);
                list.add(f);
            }
            // 关闭线程池
            pool.shutdown();
    
            // 获取所有并发任务的运行结果
            try {
                for (Future f : list) {
                    // 从Future对象上获取任务的返回值,并输出到控制台
                    System.out.println("executor" + f.get().toString());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
    
    
        }
    }
    
    class MyCallable implements Callable<Object> {
        private String name;
    
        MyCallable(String name) {
            this.name = name;
        }
    
        public Object call() {
            for (int i = 0; i < 100; i++) {
                System.out.println(name + " : " + i);
            }
            return name + " end";
        }
    
    }

    二、Thread介绍

    public class ThreadTest extends Thread {
    
        private String name;
    
        public ThreadTest(String name) {
            this.name = name;
        }
    
        @Override
        public void run() {
            System.out.println("返回当前线程的线程组中活动线程的数目 " + name + " : " + Thread.activeCount());
            System.out.println("返回对当前正在执行的线程对象的引用 " + name + " : " + Thread.currentThread());
            try {
                for (int i = 0; i < 100; i++) {
                    Thread.currentThread().sleep(1);
                    System.out.println(name + " thread : " + i);
                    //Thread.currentThread().interrupt();//中断线程
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            ThreadTest tt1 = new ThreadTest("tt1");
            tt1.setName("t1");//改变线程名称,使之与参数 name 相同
            tt1.start();//使该线程开始执行;Java 虚拟机调用该线程的 run 方法
    
            System.out.println("返回该线程的标识符 tt1 : " + tt1.getId());
            System.out.println("返回该线程的名称 tt1 : " + tt1.getName());
            System.out.println("返回线程的优先级 tt1 : " + tt1.getPriority());
            System.out.println("返回该线程的状态 tt1 : " + tt1.getState());
    
            System.out.println("测试线程是否处于活动状态 tt1 : " + tt1.isAlive());
            System.out.println("测试当前线程是否已经中断 tt1 : " + tt1.isInterrupted());
            System.out.println("测试该线程是否为守护线程 tt1 : " + tt1.isDaemon());
    
            ThreadTest tt2 = new ThreadTest("tt2");
            tt2.setName("t2");
            System.out.println("返回线程的优先级 tt2 : " + tt2.getPriority());
            tt1.yield();//暂停当前正在执行的线程对象,并执行其他线程
            try {
                //tt1.join();//等待该线程终止
                tt1.join(10);//等待该线程终止的时间最长为 millis 毫秒
                //tt1.join(10, 10);//等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            tt2.start();
        }
    }

    三、Thread与Runnable的区别

    1、Runnable方式可以避免Tread方式由于java单继承特性带来的缺陷。Runnable的代码可以被多个线程(Thread实例)共享,适合于多个线程处理同一资源的情况。如下

    public class TreadAndRunnable {
    
        public static void main(String[] args) {
            //会输出15行,每个线程都分配了一个count
            ThreadTest tt1 = new ThreadTest("线程1");
            ThreadTest tt2 = new ThreadTest("线程2");
            ThreadTest tt3 = new ThreadTest("线程3");
            tt1.start();
            tt2.start();
            tt3.start();
    
            //会输出5行,count被3个线程共享
            RunnableTest rt = new RunnableTest();
            Thread t1 = new Thread(rt, "线程1");
            Thread t2 = new Thread(rt, "线程2");
            Thread t3 = new Thread(rt, "线程3");
            t1.start();
            t2.start();
            t3.start();
        }
    
    }
    
    class ThreadTest extends Thread {
    
        private int count = 5;
        private String name;
    
        public ThreadTest(String name) {
            this.name = name;
        }
    
        @Override
        public void run() {
            while (count > 0) {
                count--;
                System.out.println(name + " 剩余 : " + count);
            }
        }
    }
    
    class RunnableTest implements Runnable{
    
        private int count = 5;
    
        public void run() {
            while (count > 0) {
                count--;
                System.out.println(Thread.currentThread().getName() + " 剩余 : " + count);
            }
        }
    }

    四、线程的生命周期

      就绪:创建线程对象后,调用了线程的start()方法(此时线程只是进入了线程队列,等待获取CPU服务,具备了运行条件,但并没有开始运行)

      运行:处于就绪状态的线程,一旦获取了CPU资源,便进入到运行状态,开始执行run()方法里面的逻辑

      终止:线程的run()方法执行完毕,或者线程调用了stop()方法,线程便进入终止状态。

      阻塞:一个正在执行的线程在某些情况下,由于某种原因而暂时让出了CPU资源,暂停了自己的执行,便进入了阻塞状态,如调用了sleep()方法。

    五、线程的分类

    用户线程:运行在前台,执行具体任务

    守护线程:运行在后台,为其他前台线程服务。一旦所有用户线程都结束运行,守护线程会随JVM一起结束工作(如数据库连接池中的监测线程,JVM启动后的检测线程)

      守护线程的设置,必须在start()方法前调用setDaemon(true)设置当前线程为守护线程,否则会抛出IllegalThreadStateException异常;守护线程中产生的线程也是守护线程;不是所有的任务都可以分配给守护线程来执行如读写,计算逻辑等(因为守护线程会在用户线程结束后结束)。

    jstack工具:(是window自带工具,在命令行直接可以使用)

      作用:生成JVM当前时刻线程快照,即当前进程所有线程消息。

      目的:帮助定位程序问题出现的原因,如长时间停顿、CPU占用率过高等。

      使用:在命令行输入jstack pid(进程id,在任务管理器中可以查看到)

    JAVA多线程实现的三种方式

    Java总结篇系列:Java多线程(一)

  • 相关阅读:
    LeetCode Binary Tree Inorder Traversal
    LeetCode Populating Next Right Pointers in Each Node
    LeetCode Construct Binary Tree from Inorder and Postorder Traversal
    LeetCode Reverse Linked List II
    LeetCode Populating Next Right Pointers in Each Node II
    LeetCode Pascal's Triangle
    Palindrome Construct Binary Tree from Preorder and Inorder Traversal
    Pascal's Triangle II
    LeetCode Word Ladder
    LeetCode Binary Tree Zigzag Level Order Traversal
  • 原文地址:https://www.cnblogs.com/sunjf/p/java_thread.html
Copyright © 2011-2022 走看看