JavaEE_____多线程2

一. 多线程

1.线程常见的构造方法

方法 说明
Thread() 创建线程对象
Thread(Runnable target) 使用Runnable对象创建线程对象
Thread (String name) 创建线程对象并命名
Thread (Runnable target ,String name) 使用Runnable对象创建线程对象并命名
Thread(ThreadGroup group,Runnable target) 线程可以被用来分组管理,分好的组即为线程组

1.1具体使用:

public class ThreadDemo10 {
    
    
    public static void main(String[] args) {
    
    

        //创建线程并设置线程名称
        Thread t = new Thread("线程1") {
    
    
            @Override
            public void run() {
    
    
                //休眠线程
                try {
    
    
                    Thread.sleep(60*60*1000);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        };
        //启动线程
        t.start();
    }
}

public class ThreadDemo11 {
    
    
    public static void main(String[] args) {
    
    

        Thread thread = new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                try {
    
    
                    Thread.sleep(60*60*1000);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        },"Runnable-Thread");

        thread.start();
    }
}

public class ThreadDemo10 {
    
    
    public static void main(String[] args) {
    
    

        //创建线程并设置线程名称
        Thread t = new Thread("线程1") {
    
    
            @Override
            public void run() {
    
    
                //休眠线程
                try {
    
    
                    Thread.sleep(60*60*1000);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        };
        //启动线程
        t.start();
    }
}

1.2 线程分组使用

import java.security.acl.Group;
import java.util.Random;

public class ThreadDemo12 {
    
    
    public static void main(String[] args) {
    
    
        //创建一个线程分组 (女子100米比赛)
        ThreadGroup group = new ThreadGroup("thread-group");

        //2.定义一个公共的任务(线程的任务)
        Runnable runTask = new Runnable() {
    
    
            @Override
            public void run() {
    
    //具体业务
                //生成一个1到3秒的随机数
                int num = (1 + new Random().nextInt(3));
                try {
    
    
                    //跑了n秒到达终点
                    Thread.sleep(num*1000);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                System.out.println("选手到达终点:" + num + "s");
            }
        }78

        //3.线程(运动员)
        Thread t1 = new Thread(group,runTask);//选手1,2,3
        Thread t2 = new Thread(group,runTask);
        Thread t3 = new Thread(group,runTask);

        //开始
        t1.start();
        t2.start();
        t3.start();

        //所有人全部到达终点之后宣布成绩
        while (group.activeCount() > 0) {
    
    
        }
            System.out.println("宣布比赛成绩");
    }
}

在这里插入图片描述

2. 线程常用属性

属性 获取方法
ID getId()
名称 getName()
状态 getState()
优先级 getPriority()
是否守护(后台)进程 isDaemon()
是否存活 isAlive()
是否被中断 isInyerrupted()

(1). ID是线程的唯一标识,不同线程不会重复。
(2). 名称是各种调试工具用到
(3). 状态表示线程当前所处的一个情况
(4). 优先级高的线程理论上来说更容易被调度到
(5). 关于守护线程(后台线程),需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。
(6).是否存活,即为run方法是否运行结束了
(7)
优先级:

ublic class ThreadDemoByPriority2 {
    
    
    private final static int MAXCOUNT = 1000;
    public static void main(String[] args) {
    
    
        Thread t1 = new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                //得到当前线程
                Thread t = Thread.currentThread();
                int priority = t.getPriority();//得到线程优先级
                for (int i = 0; i < 1000 ; i++) {
    
    
                    System.out.println(t.getName() + " --优先级" + priority);

                }
            }
        },"线程1");
        t1.setPriority(Thread.MAX_PRIORITY);

        Thread t2 =new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                Thread t = Thread.currentThread();
                int priority = t.getPriority();//得到线程优先级
                for (int i = 0; i < 1000 ; i++) {
    
    
                    System.out.println(t.getName() + " --优先级" + priority);
                }
                }
        },"线程2");

        t2.setPriority(Thread.MIN_PRIORITY);


        Thread t3 = new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                Thread t = Thread.currentThread();
                int priority = t.getPriority();//得到线程优先级
                for (int i = 0; i < 1000 ; i++) {
    
    
                    System.out.println(t.getName() + " --优先级" + priority);
                }

            }
        },"线程3");
        t3.setPriority(Thread.NORM_PRIORITY);

        //同时启动线程
        t2.start();
        t1.start();
        t3.start();

    }
}

在这里插入图片描述

结论:优先级高的大概率先执行

isAlive

public class ThreadDemoByAlive {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Thread t = new Thread(()->{
    
    
            Thread thread = Thread.currentThread();
            System.out.println("线程是否存活2: " + thread.isAlive());
        });
        System.out.println("线程是否存活1 " + t.isAlive());
        t.start();
        System.out.println("线程是否存活3 " + t.isAlive());
        Thread.sleep(1000);
        System.out.println("线程是否存活4 " + t.isAlive());
    }
}

-

3. 守护线程

public class ThreadDemoByDameon {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        //得到当前的线程
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName() + "--是否是守护线程 " + thread.isDaemon());

        Thread t1 = new Thread(()->{
    
    
            //得到当前线程
            Thread cThread = Thread.currentThread();
            System.out.println(cThread.getName() + "--是否为守护线程 " + cThread.isDaemon());


        Thread tt1 = new Thread(()->{
    
    
            Thread cThread2 = Thread.currentThread();
            System.out.println(cThread2.getName() + "--是否为守护线程" +cThread2.isDaemon());
        },"子线程的子线程1");
        tt1.start();

        },"子线程1");



        //手动指定线程为守护线程
        t1.setDaemon(true);


        t1.start();//启动线程

        Thread.sleep(1000);
    }
}

在这里插入图片描述

4.守护线程 VS 用户线程

在这里插入图片描述
在这里插入图片描述

结论

  1. JVM 会等待所有的用户线程执行完成后,再退出,但JVM 不会等待守护线程执行完再退出。
  2. 守护线程是为用户线程服务的,没有了用户线程之后,守护线程也没有存在的必要了。
    区别
    用户线程在Java程序中比较重要,JVM一定要等所有的用户线程执行完后才能自然结束,而守护线程就不一样了,守护线程是为用户线程服务的,当所有的用户线程执行完后,不管守护线程是否执行,JVM都会退出执行。

二. 线程的常用方法

1. 线程等待 join——李四接班

有时,我们需要等待一个线程执行完它的工作后,才能进行自己的下一步工作。

方法 说明
public void join() 等待线程结束
public void join(long mills) 等待线程结束,最多等待 mills 毫秒
public void join(long mills,int nanos) 同理,但是可以更高精度
/*
* join
* */
public class ThreadByJoin {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    

        Thread t1 = new Thread(()->{
    
    
            //1.张三开始上班
            System.out.println("1.张三开始上班");
            //2.张三正在上班
            try {
    
    
                Thread.sleep(1000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            //3.张三下班
            System.out.println("3. 张三下班");
        });
        //启动程序
        t1.start();

        t1.join();

        Thread t2 = new Thread(()->{
    
    
            //1.李四开始上班
            System.out.println("1.李四开始上班");
            //2.李四正在上班
            try {
    
    
                Thread.sleep(1000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            //3.李四下班
            System.out.println("3.李四下班");
        });
        t2.start();
    }
}

在这里插入图片描述
优点:

  1. 写法优雅
  2. 运行时所用的资源更少

2. 线程的终止

2.1 使用自定义标识符终止线程

public class ThreadInterrupet {
    
    

    //1.声明一个自定义标识符
    private static boolean flag = false;

    public static void main(String[] args) throws InterruptedException {
    
    
        Thread thread = new Thread(()->{
    
    
            while (!flag){
    
    
                System.out.println("正在转账....");
                try {
    
    
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
            System.out.println("啊? 差点误了大事!");
        });
        thread.start();

        Thread.sleep(3000);
        //终止线程
        System.out.println("有内鬼,终止交易");
        flag = true;
    }
}

在这里插入图片描述

2.2 使用 interrupt() 终止线程

public class ThreadInterrupt2 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    

        Thread thread = new Thread(()->{
    
    
            while (!Thread.interrupted()){
    
    
                System.out.println("正在转账...");
            }
            System.out.println("险些误了大事");
        });

        thread.start();

        Thread.sleep(100);
        //终止线程
        thread.interrupt();
        System.out.println("有内鬼,终止交易");
    }
}

在这里插入图片描述
interrupt() 需要配合Thread.currentThread().isInterrupted() 或 Thread.interrupted() 一块使用,从而实现线程的终止。

2.3 isinterrupted和interrupted 的区别:

  1. interrupted 属于静态方法,所有程序都可以直接调用的全局方法;而isinterrupted 属于某个实例的方法。
  2. interrupted 在使用完之后会重置终端标识符,而isinterrupted 不会中断标识符。

3. yield 让出执行权

yield:让出CPU的执行权

public class ThreadYield {
    
    
    public static void main(String[] args) {
    
    
        Thread t1 = new Thread(()->{
    
    
            Thread cThread = Thread.currentThread();
            for (int i = 0; i < 100; i++) {
    
    
                //让出CPU执行权
                Thread.yield();
                System.out.println("执行了线程 " + cThread.getName());
            }
        },"张三");
        t1.start();

        new Thread(()->{
    
    
            Thread cThread = Thread.currentThread();
            for (int i = 0; i < 100; i++) {
    
    
                System.out.println("执行线程:" + cThread.getName());

            }
        },"李四").start();

    }
}

在这里插入图片描述
yield 方法会让CPU的执行权,让线程调度器重新调度线程,但是还有一定的记录再一次调用到出让CPU的线程上的,这一次它就会执行线程的方法了,因为yield已经被执行过。

4.获取当前线程

方法 说明
public static Thread currentHread(); 返回当前线程对象引用

在这里插入图片描述

5.问题:在主线程中创建两个子线程,每个子线程中产生一个随机数,最终等待子线程执行完成之后,在主线程累计两个子线程的结果。

import java.util.Random;

public class ThreadDemo14 {
    
    
    static int num1 = 0;
    static int num2 = 0;
    public static void main(String[] args) throws InterruptedException {
    
    

        Thread t1 = new Thread(()->{
    
    
            num1 = new Random().nextInt(10);
        });
        t1.start();

        Thread t2 = new Thread(()->{
    
    
            num2 = new Random().nextInt(10);

        });
        t2.start();

        t1.join();
        t2.join();
        System.out.println("最终的结果: " + (num1 + num2));
    }
}

![在这里插入图片描述](https://img-blog.csdnimg.cn/36e696a8e06d49358458707c78ff5572.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5ryr5aSpIOaYn-i-sA==,size_20,color_FFFFFF,t_70 ,g_se,x_16)

6. 休眠当前线程

1)使用sleep休眠
2)使用TimeUtil 休眠

6.1 使用sleep休眠

方法 说明
public static void sleep(long mills) throws InterruptedException 休眠当前线程 mills毫秒
public static void sleep(long mills,int nanos) throws InterruptedException 可以更高精度的休眠
public class ThreadSleep {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    

        Thread thread = new Thread(()->{
    
    
            try {
    
    
                Thread.sleep(60*60*1000);
            } catch (InterruptedException e) {
    
    
              //  e.printStackTrace();
                System.out.println("我接受到了终止执行的通知");
            }
        });

        thread.start();
        Thread.sleep(1000);
        System.out.println("终止子线程");
        thread.interrupt();
    }
}

在这里插入图片描述
缺点: 休眠长时间 不好计算

6.2 使用TimeUtil 休眠

在这里插入图片描述
实现原理:
在这里插入图片描述

三. 线程状态

3.1 所有线程状态(6种)

在这里插入图片描述
NEW:新建状态,当线程被创建,但是未启动start方法之前的状态。
RUNNABLE: 运行状态,得到时间片运行中。Ready:就绪状态,未得到时间片。
BLOCKED: 阻塞状态,遇到锁就会造成阻塞状态等待另一个线程释放锁。
WAITING:无限期等待状态。
TIMED_WAITING: 有明确结束时间的等待状态。
在这里插入图片描述

TERMINATED:销毁状态,当线程结束之后就会变成此状态。
在这里插入图片描述
在这里插入图片描述
得到当前线程的状态
线程状态的转变

import java.util.concurrent.TimeUnit;

public class ThreadState {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    

        Thread t1 = new Thread(()->{
    
    
            System.out.println("当前线程状态2: " + Thread.currentThread().getState());
            try {
    
    
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        });
        System.out.println("当前线程状态:" + t1.getState());
        t1.start();

       //让主线程休眠1秒
        Thread.sleep(1000);
        System.out.println("当前线程状态3:" + t1.getState());

        //等待子线程执行完
        t1.join();
        System.out.println("当前线程的状态4:" + t1.getState());

    }

    private static void printState() {
    
    
       for (Thread.State item: Thread.State.values()){
    
    
            System.out.println(item);
        }
    }
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/biteqq/article/details/123671474
今日推荐