【Java基础8】多线程

多线程

一、概念题

  1. 简述程序、进程和线程之间的关系,什么是多线程程序?
  • 程序:指令和数据的有序集合,其本身没有任何运行含义。是一个静态的概念。

  • 进程:执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位

  • 线程:通常一个进程中可以包含若干个线程,线程是cpu调度和执行的单位,是独立的执行路径。eg:main()称之为主线程,是系统的入口,用于执行整个程序

    多线程程序:

    很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核(如服务器),如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,但是切换的很快。

  1. 线程有哪五个基本状态?他们之间如何转化?简述线程的生命周期。

    • 新建状态:
      使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它将保持这个状态直到程序 start() 这个线程。

    • 就绪状态:
      当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。

    • 运行状态:
      如果就绪状态的线程获取 CPU 资源,就可以执行run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。

    • 阻塞状态:

      如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:

      • 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
      • 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
      • 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
    • 死亡状态:
      一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。

  2. Runable接口中包括哪些抽象方法?Thread类中有哪写主要的成员变量和方法?

    Runnable接口中仅有run()抽象方法。
    Thread类主要域有:MAX_PRIORITY,MIN_PRIORITY,NORM_PRIORITY。
    主要方法有start(),run(),sleep(),currentThread(),setPriority(),getPriority(),join()等。

  3. start()方法和run()方法的区别,sleep()和wait()的异同

    start()方法和run()方法的区别:

    ​ 只有调用了start()方法,才会表现出多线程的特性,使不同线程的run()方法里面的代码交替执行。

    ​ 如果只是调用run()方法,必须等待一个线程的run()方法里面的代码全部执行完毕之后,另外一个线程才可以执行其run()方法里面 的代码。

    sleep()和wait()的异同:

    ​ sleep方法和wait方法都可以用来放弃CPU一定的时间

    ​ 不同点在于如果线程持有某个对象的监视器,sleep方法不会放弃这个对象的监视器,wait方法会放弃这个对象的监视器

  4. 如何在java程序中实现多线程?简述使用Thread字类和实现Runnable接口两种方法的异同。

    因为实现接口的方式比继承类的方式更灵活,也能减少程序之间的耦合度,符合设计模式6大原则的核心——>面向接口编程。

  5. 了解lambada表达式(了解即可)

    package com.Thread;
    
    public class TestLambda1 {
        //3.静态内部类
        static class Like2 implements ILike{
            @Override
            public void lambda() {
                System.out.println("i like lambda2");
            }
        }
    
        public static void main(String[] args) {
            ILike like = new Like();
            like.lambda();
    
            like = new Like2();
            like.lambda();
    
            //4.局部内部类
            class Like3 implements ILike{
                @Override
                public void lambda() {
                    System.out.println("i like lambda3");
                }
            }
    
            like = new Like3();
            like.lambda();
    
            //5.匿名内部类,没有类的名称,必须借助接口或者父类
            like = new ILike() {
                @Override
                public void lambda() {
                    System.out.println("i like lambda4");
                }
            };
            like.lambda();
    
            //6.用lambda简化
            like = ()->{
                System.out.println("i like lambda5");
            };
    
            like.lambda();
            
    /*
            简化1.参数类型
            like = (a)->{
                System.out.println("i like lambda5");
            };
    
            简化2.简化括号
            like = a->{
                System.out.println("i like lambda5");
            };
    
            简化3.去掉花括号(代码只有一行的情况下)
            like = a->System.out.println("i like lambda5");
    */
    
        }
    }
    
    
    //1.定义一个函数式接口(就是只有一个方法的类)
    interface ILike{
            void lambda();
    }
    
    //2.实现类
    class Like implements ILike{
        @Override
        public void lambda() {
            System.out.println("i like lambda1");
        }
    }
    

二、编程题

  1. 使用Thread.sleep()编写一个倒计时10秒的java程序,输出10,9,8…1;

    public static void main(String[] args) {
        try {
            tenDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    public static void tenDown() throws InterruptedException {
        int num = 10;
        while (true){
            Thread.sleep(1000);
            System.out.println(num--);
            if (num<=0){
                break;
            }
        }
    }
    
  2. 三个黄牛同时抢200张票,打印出哪个黄牛买了第几张票

    public class demo02 {
        public static void main(String[] args) {
            BuyTicket station = new BuyTicket();
            new Thread(station,"黄牛A").start();
            new Thread(station,"黄牛B").start();
            new Thread(station,"黄牛C").start();
        }
    }
    
    class BuyTicket implements Runnable{
        //票
        private  int ticketNums = 200;
        boolean flag = true;//外部停止方法
        @Override
        public void run() {
            //买票
            while (flag){
                try {
                    //模拟延迟
                    Thread.sleep(100);
                    buy();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        private synchronized void buy(){
            //判断是否有票
            if (ticketNums<=0){
                flag = false;
                return;
            }
            //买票显示
            System.out.println(Thread.currentThread().getName()+"拿到第"+ticketNums--+"张票");
        }
    }
    
  3. 编写一个程序,启动三个线程,三个线程的ID分别是A,B,C;每个线程将自己的ID值在屏幕上打印5遍,打印顺序是ABCABC…重复三遍

    public class demo03 {
        private static Lock lock = new ReentrantLock();
        private static int state = 0;//通过state的值来判断是否打印
        private static int count =15;
    
        static class ThreadA extends Thread {
            @Override
            public void run() {
                for (int i = 0; i < count;) {
                    try {
                        lock.lock();
                        while (state %3 == 0) {
                            System.out.print("A");
                            state++;
                            i++;
                        }
                    } finally {
                        lock.unlock();
                    }
                }
            }
        }
    
        static class ThreadB extends Thread {
            @Override
            public void run() {
                for (int i = 0; i < count;) {
                    try {
                        lock.lock();
                        while (state %3 == 1) {
                            System.out.print("B");
                            state++;
                            i++;
                        }
                    } finally {
                        lock.unlock();
                    }
                }
            }
        }
    
        static class ThreadC extends Thread {
            @Override
            public void run() {
                for (int i = 0; i < count;) {
                    try {
                        lock.lock();
                        while (state %3 == 2) {
                            System.out.print("C");
                            state++;
                            i++;
                            if (state==15){
                                System.out.println('\n');
                                state=0;
                            }
                        }
                    } finally {
                        lock.unlock();
                    }
                }
            }
        }
    
        public static void main(String[] args) {
            new ThreadA().start();
            new ThreadB().start();
            new ThreadC().start();
        }
    }
    

三、挑战题

1.制作一个给定时间的倒计时器

package java0018;

import java.util.Scanner;

public class demo04 {
    public static void main(String[] args) {
        try {
            timeDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void timeDown() throws InterruptedException {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入倒计时时间:");
        int time = scanner.nextInt();
        while (true){
            int hh = time /60 /60;
            int mm = (time-hh*3600) / 60;
            int ss = (time-hh*3600-mm*60) ;
            Thread.sleep(1000);
            time--;
            System.out.println(hh+"时"+mm+"分"+ss+"秒");
            scanner.close();
                if (time<=0){
                 break;
             }
        }
    }
}

2.编写一个java程序,同时用冒泡排序和选择排序实现对一个整型数组的排序,试着输出一下他们的运行时间,如果能实现更多的排序也可以尝试一下

提示

给出了一些代码,请补充完整。

可以跟着参考代码敲理解,主要是对排序和多线程的综合应用,对多线程知识要求不高。

当然如果可以独立写出来可不看提示代码独立完成。

package java0018;

//Sort类
class Sort implements Runnable{
    int [] data;
    public Sort(int [] data){
        super();
        this.data = data;
    }
    @Override
    public void run() {
        long start = System.nanoTime();
        sort();
        long end = System.nanoTime();
        System.out.println(Thread.currentThread().getName()+"执行花费了"+(end-start)+"ns");
    }
    public void sort(){
        throw new RuntimeException("在子类重写此方法");
    }
}
//BubbleSort类       冒泡排序
class BubbleSort extends Sort{
    public BubbleSort(int[] data) {
        super(data);
    }
    @Override
    public void sort(){
        try {
            sort(data);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    void sort(int[] data)throws Exception{
        /*
        冒泡排序的代码
         */
        int temp;
        for (int i = 0; i < data.length-1; i++) {
            for (int j = i+1; j < data.length; j++) {
                if (data[j]>data[i]){
                    temp = data[i];
                    data[i] = data[j];
                    data[j] = temp;
                }
            }
        }

    }
}
//选择排序SelectionSort类        选择排序
class SelectionSort extends Sort{
    public SelectionSort(int[] data) {
        super(data);
    }
    @Override
    public void sort(){
        try {
            sort(data);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    void sort(int[] data)throws Exception{
         /*
        选择排序的代码
         */
         int temp;
         int k;
        for (int i = 0; i < data.length-1; i++) {
            k=i;
            for (int j = i+1; j < data.length; j++) {
                if (data[k] < data[j]){
                    k = j;
                }
            }
            if (k != i){
                temp = data[i];
                data[i] = data[k];
                data[k] = temp;
            }
        }

    }
}
public class MainTest {
    public static void main(String[] args) {
        final  int count = 10;
        int[] data = createData(count);
        //=====?????==========复制数组 请补充 思考一下为什么要复制=======??????==========
        int[] data1 = new int[count];
        for (int i = 0; i < data.length; i++) {
            data1[i] = data[i];
        }
        //创建冒泡排序线程 
        Sort s1 = new BubbleSort(data1);
        //创造选择排序线程 
        Sort s2 = new SelectionSort(data1);
        //启动线程 
        new Thread(s1,"冒泡排序:").start();
        new Thread(s2,"选择排序:").start();
    }
    /*
    创造数组方法,参数为数组大小;
     */
    private static int [] createData(int count){
        int [] data  = new int[count];
        for (int i = 0 ; i < data.length;i++){
            data[i] = (int)(Math.random()*count);
        }
        return data;
    }
}


BubbleSort(data1);
        //创造选择排序线程 
        Sort s2 = new SelectionSort(data1);
        //启动线程 
        new Thread(s1,"冒泡排序:").start();
        new Thread(s2,"选择排序:").start();
    }
    /*
    创造数组方法,参数为数组大小;
     */
    private static int [] createData(int count){
        int [] data  = new int[count];
        for (int i = 0 ; i < data.length;i++){
            data[i] = (int)(Math.random()*count);
        }
        return data;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值