zoukankan      html  css  js  c++  java
  • Java的多线程1:线程的使用

    概述

    进程是线程的容器,线程共享进程的内存空间,所以线程之间彼此通信是比较容易的,而线程又有自己本地内存地址(jmm抽象概念,并不真实存在),其他线程无法访问。了解进程和线程关系,可以看我另一篇博客《进程与线程》

    Java创建线程的两种方式

    继承Thread类

    public class ThreadDemo1 extends Thread {
    
        @Override
        public void run(){
            for (int i = 0; i < 10; i++) {
                System.out.println("当前执行的线程是" + Thread.currentThread().getName());
            }
        }
    
        public static void main(String[] args) {
            ThreadDemo1 threadDemo1 = new ThreadDemo1();
            ThreadDemo1 threadDemo2 = new ThreadDemo1();
            threadDemo1.start();
            threadDemo2.start();
        }
    }

    执行结果是不确定的

    实现Runnable

    public class ThreadDemo2 implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                for (int j = 0;j < 1000; ++j){
                    System.out.println(i + "当前执行的线程是" + Thread.currentThread().getName());
                }
            }
        }
    
        public static void main(String[] args) {
            ThreadDemo2 threadDemo1 = new ThreadDemo2();
            ThreadDemo2 threadDemo2 = new ThreadDemo2();
            Thread thread1 = new Thread(threadDemo1);
            Thread thread2 = new Thread(threadDemo2);
            thread1.start();
            thread2.start();
            System.out.println("当前线程是===>" + Thread.currentThread().getName());
        }
    }

    主线程的名字为main,非主线程的名字是由虚拟机来指定的,同时,我们也可以为线程指定具体的名称。

     我们保证每个线程都能正常启动,并不意味着它会按顺序的执行,因为调度程序是无法保证它的执行次序的,同时,run()函数结束时,意味着该线程的任务完成了。

    注意:调用线程要调用start,如果调用run,那仅仅是简单的对象调用。

    线程生命周期

        public enum State {
            /**
             * Thread state for a thread which has not yet started.
             */
            NEW,
    
            /**
             * Thread state for a runnable thread.  A thread in the runnable
             * state is executing in the Java virtual machine but it may
             * be waiting for other resources from the operating system
             * such as processor.
             */
            RUNNABLE,
    
            /**
             * Thread state for a thread blocked waiting for a monitor lock.
             * A thread in the blocked state is waiting for a monitor lock
             * to enter a synchronized block/method or
             * reenter a synchronized block/method after calling
             * {@link Object#wait() Object.wait}.
             */
            BLOCKED,
    
            /**
             * Thread state for a waiting thread.
             * A thread is in the waiting state due to calling one of the
             * following methods:
             * <ul>
             *   <li>{@link Object#wait() Object.wait} with no timeout</li>
             *   <li>{@link #join() Thread.join} with no timeout</li>
             *   <li>{@link LockSupport#park() LockSupport.park}</li>
             * </ul>
             *
             * <p>A thread in the waiting state is waiting for another thread to
             * perform a particular action.
             *
             * For example, a thread that has called <tt>Object.wait()</tt>
             * on an object is waiting for another thread to call
             * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
             * that object. A thread that has called <tt>Thread.join()</tt>
             * is waiting for a specified thread to terminate.
             */
            WAITING,
    
            /**
             * Thread state for a waiting thread with a specified waiting time.
             * A thread is in the timed waiting state due to calling one of
             * the following methods with a specified positive waiting time:
             * <ul>
             *   <li>{@link #sleep Thread.sleep}</li>
             *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
             *   <li>{@link #join(long) Thread.join} with timeout</li>
             *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
             *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
             * </ul>
             */
            TIMED_WAITING,
    
            /**
             * Thread state for a terminated thread.
             * The thread has completed execution.
             */
            TERMINATED;
        }

    新建状态

    线程对象创建后,就进入新建状态  Thread thread = new Thread

    就绪状态

    调用start()方法,线程进入就绪状态,但并不意味着线程就立即执行,只是说明此线程已经做好准备,随时等待CPU调度执行。

    阻塞状态

    多个线程同时竞争一个独占锁,其他未抢到锁的线程,就进入阻塞状态被放置到锁池中,直到获取到锁,进入就绪状态

    等待状态

    该线程需要等待其他线程做出一些特定动作,通知或者是中断,等待其被其他线程唤醒,像CountDownLatch就可以等待一个或者几个线程结束。

    超时等待状态

    和等待状态不同的是,它可以在指定的时间自行的返回,sheep(long)函数就会让线程进入超时等待状态,时间到了才会转入就绪状态。

    运行状态(Running)

    CPU调度处于就绪状态的线程时,这个线程才真正执行,进入运行状态。

    终止状态

    线程正常执行完毕后或提前强制性终止或出现异常,线程就要销毁,释放资源。

    线程的方法调用

    获取线程基本信息

    public class ThreadDemo6 {
        public static void main(String[] args) {
            Thread thread = new Thread(){
                @Override
                public void run(){
                    /*获取线程唯一id标识*/
                    long id = this.getId();
                    System.out.println("thread的ID==>" + id);
    
                    /*获取线程名字*/
                    String name = this.getName();
                    System.out.println("thread的名字==>" + name);
    
                    /*获取线程的优先级 默认5 1-10*/
                    int priority = this.getPriority();
                    System.out.println("thread的优先等级==>" + priority);
    
                    /*查看当前线程是否为守护线程*/
                    boolean isDaemon = this.isDaemon();
                    System.out.println("thread是否为守护线程==>" + isDaemon);
    
                    /*查看线程是否被中断*/
                    boolean isInterrupted = this.isInterrupted();
                    System.out.println("thread是否被中断==>" + isInterrupted);
                }
            };
            thread.start();
        }
    }

    执行结果

    thread的ID==>11
    thread的名字==>Thread-0
    thread的优先等级==>5
    thread是否为守护线程==>false
    thread是否被中断==>false

    Thread.yield()

    public class ThreadDemo1 implements Runnable {
        protected int countDown = 10;
        private static int taskCount = 0;
        private final int id = taskCount++;
        public ThreadDemo1(){}
        public ThreadDemo1(int countDown){
            this.countDown = countDown;
        }
        public String status(){
            return "#" + id + "(" + (countDown > 0 ? countDown : "stop!") + ")";
        }
    
    
        @Override
        public void run() {
            while (countDown-- > 0){
                System.out.println(status() + "  ");
                Thread.yield();
            }
        }
    
        public static void main(String[] args) {
            for (int i = 0; i < 3; i++){
                new Thread(new ThreadDemo1()).start();
            }
        }
    }
    #0(9)#0(8)#0(7)#0(6)#0(5)#0(4)#0(3)#0(2)#0(1)#0(stop!)
    #1(9)#1(8)#1(7)#1(6)#1(5)#1(4)#1(3)#1(2)#1(1)#1(stop!)
    #2(9)#2(8)#2(7)#2(6)#2(5)#2(4)#2(3)#2(2)#2(1)#2(stop!)

    这个是一个倒计时的任务,对Thread.yield()调用是对线程调度器的一种建议,它在声明“我已经执行完生命周期中最重要的部分了,此刻正是切换给其他任务执行一段时间的大好时机”,说白就是自己按暂停键,让出自己CPU的使用权限,转为就绪状态,至于下一次什么时候能获得CPU调度就不一定了,有时很快,有时得等上一会。

    Thread.sleep

    public class ThreadDemo1 implements Runnable {
        protected int countDown = 10;
        private static int taskCount = 0;
        private final int id = taskCount++;
        public ThreadDemo1(){}
        public ThreadDemo1(int countDown){
            this.countDown = countDown;
        }
        public String status(){
            return "#" + id + "(" + (countDown > 0 ? countDown : "stop!") + ")";
        }
    
    
        @Override
        public void run() {
            try {
                while (countDown-- > 0){
                    System.out.println(status());
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
        }
    
        public static void main(String[] args) {
            for (int i = 0; i < 3; i++){
                new Thread(new ThreadDemo1()).start();
            }
        }
    }

    Thread.sleep(long)将使“正在执行的任务“中止执行给定的时间(暂停执行)并且让出CPU使用权,这个语句相当于说在接下来的1秒内,你都不要叫我,我想睡一会,1秒睡眠时间过后,它自动转为就绪状态,但CPU不一定马上执行这个睡醒的线程,这要取决于是否抢到CPU时间片段。值得注意的是如果sleep和yield上下文被加锁了,它们依然使用锁,不会去释放。而sleep与yield最大的不同是,yield不会让线程进入等待状态,只是把线程转为就绪状态,并把CPU执行机会让步给优先级相同或者更高的线程,而sleep能控制具体交出CPU的使用时间。

    Thread.currentThread()

    public class ThreadDemo2 extends Thread {
        static {
            System.out.println("静态块执行的线程===>" + Thread.currentThread().getName());
        }
        {
            System.out.println("非静态块执行的线程是====>" + Thread.currentThread().getName());
            System.out.println("this.getName()1=====>" + this.getName());
        }
    
        public ThreadDemo2(){
            System.out.println("构造方法内执行的线程====>" + Thread.currentThread().getName());
            System.out.println("this.getName()2=====>" + this.getName());
        }
    
        @Override
        public void run() {
            System.out.println("当前执行的线程为====>" + Thread.currentThread().getName());
            System.out.println("this.getName()3=====>" + this.getName());
        }
    
        public static void main(String[] args) {
            ThreadDemo2 threadDemo2 = new ThreadDemo2();
            threadDemo2.start();
        }
    }

    执行结果

    静态块执行的线程===>main
    非静态块执行的线程是====>main
    this.getName()1=====>Thread-0
    构造方法内执行的线程====>main
    this.getName()2=====>Thread-0
    当前执行的线程为====>Thread-0
    this.getName()3=====>Thread-0

    currentThread返回的是当前正在执行线程对象的引用,它与this.getName()有明显的不同,执行静态块,非静态块,构造方法的线程是main,而非ThreadDemo2,在执行run()方法的才是实例化的线程threadDemo2。所以在当前执行的Thread未必就是Thread本身。

    isAlive()

    public class ThreadDemo3 extends Thread {
        @Override
        public void run(){
            System.out.println("执行执行====" + this.isAlive());
        }
    
        public static void main(String[] args) {
            ThreadDemo3 threadDemo3 = new ThreadDemo3();
            System.out.println("begin===>" + threadDemo3.isAlive());
            threadDemo3.start();
            System.out.println("end==>" + threadDemo3.isAlive());
        }
    }
    begin===>false
    end==>true
    执行执行====true

    isAlive()检测线程是否处于活动状态,活动状态返回true

    setPriority()

    优先级设定,优先级高的线程越容易获取CPU使用权,

    public class ThreadDemo4 {
        public static void main(String[] args) {
            for (int i = 0; i < 5; ++i){
                Thread1 thread1 = new Thread1();
                thread1.setPriority(6);
                Thread2 thread2 = new Thread2();
                thread2.setPriority(4);
                thread2.start();
                thread1.start();
            }
        }
    }
    class Thread1 extends  Thread{
        @Override
        public void run(){
            for (int i = 0; i < 100000; ++i){
                System.out.println("+++++++++++++");
            }
        }
    }
    class Thread2 extends Thread{
    
        @Override
        public void run(){
            for (int i = 0; i < 100000; ++i){
                System.out.println("--------------");
            }
        }
    }

    执行结果

    +++++++++++++
    +++++++++++++
    +++++++++++++
    +++++++++++++
    +++++++++++++
    +++++++++++++
    +++++++++++++
    +++++++++++++
    ...

    CPU会将资源尽量让给优先级高的线程

    setDaemon()

    守护线程,也有人叫后天线程,我们创建出来的线程默认都是前台线程,在使用上来说,守护线程和前台线程是没啥区别,区别在于进程结束,当一个进程中的所有前台线程都结束时,无论这个进程中的守护线程是否还在运行都要强制将他们结束。也就是说前台线程都结束了,守护线程也会自动销毁,它是为其他线程提供便利而存在的。

    /*rose与jack*/
    public class ThreadDemo5 {
        public static void main(String[] args) {
            Rose rose = new Rose();
            Jack jack = new Jack();
            /*设置为守护线程必须在线程未启动之前*/
            jack.setDaemon(true);
            rose.start();
            jack.start();
        }
    }
    class Rose extends Thread{
        @Override
        public void run(){
            for (int i = 0; i < 5; ++i){
                System.out.println("rose: let me go!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("成功跳水");
        }
    }
    class Jack extends Thread{
        @Override
        public void run(){
            while (true){
                System.out.println("jack:you jump! i jump!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    执行结果

    rose: let me go!
    jack:you jump! i jump!
    rose: let me go!
    jack:you jump! i jump!
    rose: let me go!
    jack:you jump! i jump!
    rose: let me go!
    jack:you jump! i jump!
    rose: let me go!
    jack:you jump! i jump!
    成功跳水

    jack守护着rose,jack是守护线程,当rose跳水后,jack认为自己也没有活着的必要了,也自己销毁了,但注意一点是这当中还有一个第三者main,需要main也运行完jack线程才会销毁。

    join()

    这个方法可以协调多个线程同步运行,多线程运行本身是设计异步运行的,但在程序运行业务中,有可能线程A的计算需要线程B的返回结果,这就需要他们执行各自任务时要有先后,join就需要协调这些线程同步运行。

    public class ThreadDemo6 {
        private static boolean isFinish = false;
    
        public static void main(String[] args) {
            Thread download = new Thread(){
                @Override
                public void run(){
                    System.out.println("下载图片中.....");
                    for (int i = 1; i <= 100; ++i){
                        System.out.println("下载进度" + i + "%");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("图片下载完毕");
                    isFinish = true;
                }
            };
            Thread show = new Thread(){
                @Override
                public void run(){
                    System.out.println("开始显示图片...");
                    try {
                        download.join();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (!isFinish){
                        throw new RuntimeException("图片下载出错");
                    }
                    System.out.println("图片正常展示。。。");
                }
            };
            download.start();
            show.start();
        }
    }

    执行结果

    下载图片中.....
    开始显示图片...
    下载进度1%
    下载进度2%
    ...
    下载进度100%
    图片下载完毕
    图片正常展示。。。

    show调用join会使show无限阻塞,直到down线程销毁为止,它和sleep最大的区别是join会释放锁,而sleep不会。

    涉及到jmm内存模型,线程安全等,后面在介绍

  • 相关阅读:
    线性表链式存储方式的C语言实现
    线性表顺序存储方式的C语言实现
    抽象数据类型Triplet的C语言实现
    Python之装饰器
    Django-auth(认证系统)
    Django-中间件
    Django-form表单
    Python cookie、session和自定义分页
    Django 使用ajax上传文件
    Python之迭代器和生成器
  • 原文地址:https://www.cnblogs.com/dslx/p/12664004.html
Copyright © 2011-2022 走看看