java线程(网易大数据面试题)

Posted somelovelanguage

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java线程(网易大数据面试题)相关的知识,希望对你有一定的参考价值。

网易大数据面试题目

  1. 线程的实现方式有什么,写出来
  2. 讲一下synchronize和volatile锁的问题

一、线程的实现方式

1.继承Thread类(创建Thread类的匿名子类)

  1. 自定义类继承Thread类
  2. 重写run方法
  3. new一个自定义类,调用start方法
//1. 继承类的方式创建线程,数据未共享
Thread atm1 = new ATM();
Thread atm2 = new ATM();
atm2.start();
atm1.start();
class ATM extends Thread{
    private int money = 100;
    @Override
    public void run() {

        while (money>=0){
            System.out.println(Thread.currentThread().getName()+"-继承Thread类的atm:"+money--);
        }
    }
}

2.实现Runnable接口

  1. 自定义类实现Runnable接口
  2. 实现run方法
  3. new一个自定义类,作为参数传递到Thread类构造器中,new一个Thread类
  4. 调用Thread类的start方法

两种方式对比

  1. 优先选用Runnable,不需继承,避免了继承一个类的局限性
  2. 适合处理共享数据(不是说继承类不能处理共享数据,用代理类(单例模式+代理)也可以轻松处理共享数据)
   //2. 实现Runnable接口的方式创建线程,数据共享
ATM1 atm3 = new ATM1();
Thread thread1 = new Thread(atm3);
Thread thread2 = new Thread(atm3);
thread1.start();
thread2.start();

class ATM1 implements Runnable{
    private int money = 100;
    @Override
    public void run() {
        while (money>0){
//            try {
//                Thread.sleep(1000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            synchronized (this){
                System.out.println(Thread.currentThread().getName()+"-实现接口的atm:"+money--);
            }

        }
    }
}

3.实现Callable接口

  1. 实现Callable接口,重写call方法
  2. new一个自定义类,作为参数传入FutureTask类构造器,new一个FutureTask对象
  3. FutureTask对象作为参数传入Thread类构造器,new一个Thread对象
  4. 调用start方法
       //3. 实现Callable接口的方式创建线程
ATM2 atm2 = new ATM2();
FutureTask futureTask = new FutureTask<>(atm2);
Thread thread = new Thread(futureTask);
thread.start();

class ATM2 implements Callable{
    private int money = 100;
    @Override
    public Object call() {

        while (money>=0){
            System.out.println(Thread.currentThread().getName()+"-实现Callable接口的atm:"+money--);
        }
        return null;
    }
}

4.线程池创建线程

  1. Executors类创建一个线程池对象
  2. 设定线程池属性
  3. 调用线程池的submit方法(含run的对象)或commit方法(含call的对象),
  4. 关闭线程池
//        4. 线程池创建线程
//        创建一个线程池
ExecutorService service = Executors.newFixedThreadPool(10);

//设置线程池的属性
ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;
service1.setCorePoolSize(15);
service.execute(new ATM());//适合用于Runnable和继承Thread类
//        service.submit();//适合用于Callable
service.shutdown();

Thread类常用方法

currentThread:静态方法,返回当前执行代码的线程(Thread类的对象)

setName():为线程设定名字

getName():获取当前线程名字

start(): 启动线程

sleep(): 静态方法,让当前线程沉睡 毫秒

yield()释放当前cpu的执行权

join():在线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到b完全执行后,a才结束阻塞状态

二、线程的同步

1.synchronized

  1. 同步代码块 synchronized(同步监视器){}
  2. 同步方法(方法中只包含处理共享数据的代码)
    • 同步监视器,俗称锁,多个线程必须共用一把锁,任何一个类的对象都可以充当锁。
    • 同步方法,仍需同步监视器,只是未显式声明。
      • 非静态的同步方法,同步监视器是this
      • 静态的同步方法,同步监视器是:当前类本身(为Class的对象)

2、lock锁

  1. 新建一个lock锁
  2. 读写共享数据之前调用lock方法
  3. 结束时调用unlock方法,注意多个线程用同一把锁。
 //lock锁
ATM3 atm3 = new ATM3();
ProxyThread proxyThread1 = new ProxyThread(atm3);
ProxyThread proxyThread2 = new ProxyThread(atm3);
ProxyThread proxyThread3 = new ProxyThread(atm3);
proxyThread1.start();
proxyThread2.start();
proxyThread3.start();

class ATM3 {
    private int money = 100;
    private Lock lock = new ReentrantLock();

    public void modMoney() throws InterruptedException {
//        Thread.sleep(1000);
        while (true){
            lock.lock();
            if(money>=0)
            System.out.println(Thread.currentThread().getName()+"-继承Thread类的atm:"+money--);
            lock.unlock();
        }
    }
}
class  ProxyThread extends Thread{
    private ATM3 atm ;

    ProxyThread(ATM3 atm){
        this.atm = atm;
    }

    @Override
    public void run() {
        try {
            atm.modMoney();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

三、线程的调度

  1. 调度策略
  • 时间片

  • 抢占式:高优先级的线程抢占cpu

  1. java的调度方法
    1. 同优先级线程组成先进先出队列,使用时间片策略
    2. 对高优先级,使用优先调度的抢占式策略

线程的优先级

MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY:5 --默认优先级

获取和设置线程优先级

1. getPriority 获取线程优先级
2. setPriority设置线程优先级

高优先级的线程要抢占低优先级线程cpu的执行权,但只是从概率上讲,并不意味着只有当高优先级的线程执行完后,低优先级的线程才执行

四、线程的生命周期

JDK用Thread.State类定义了线程的几种状态
新建、就绪、阻塞、运行、死亡

五、线程通信

  1. wait() 使调用线程进入阻塞状态,并释放锁(与sleep不同)
  2. notify() 唤醒一个含有wait()的线程(优先级最高的),
  3. notifyAll():唤醒所有含有wait()的线程
说明:
  1. 上述三个方法必须使用在同步代码块或同步方法中(lock不行)
  2. 这三个方法的调用者必须是同步代码块或同步方法中的同步监视器,否则出现异常
  3. 上述三个方法定义在java.lang.Object类中
sleep()和wait()的异同
1. 相同点:一旦执行方法,都可以使得当前线程进入阻塞状态
2. 不同点:
   1. 两个方法声明的位置不同:Thread类中声明sleep(),Object类中声明wait()
   2. 调用的要求不同:sleep()可以在任何需要的场景下调用。wait()必须使用在同步代码块中
   3. 关于是否释放同步监视器:sleep()不释放,wait()释放

六、未学到 :volatile(改日再更)

以上是关于java线程(网易大数据面试题)的主要内容,如果未能解决你的问题,请参考以下文章

刚出炉的网易Linux运维面试题(附带答案)

Java进阶之光!2021必看-Java高级面试题总结

面试题:各大公司Java后端开发面试题总结 !=!未看

经验总结:Java高级工程师面试题-字节跳动,成功跳槽阿里!

web前端整套面试题--网易的面试题

2021网易Java高级面试题及答案,知识点总结+面试题解析