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多线程(一)

  • 相关阅读:
    uva10152-ShellSort
    WCF问题集锦:ReadResponse failed: The server did not return a complete response for this request.
    Android动态改变布局
    Android应用性能优化
    玩转CPU之直线
    [DB][MySql]关于取得自增字段的值、及@@IDENTITY 与并发性问题
    js对象实例化的常见三种方式
    TCP协议
    [UnityUI]循环滑动列表
    Spring MVC原理及实例基础扫盲篇
  • 原文地址:https://www.cnblogs.com/sunjf/p/java_thread.html
Copyright © 2011-2022 走看看