Day05-多线程

多线程

多线程的创建方式:

方式一:继承于Thread类

  1. 创建一个继承于Thread类的子类
  2. 重写Thread类的run() --> 将此线程执行的操作写在run()方法里面
  3. 创建Thread类的子类的对象
  4. 通过此对象调用start():启动当前线程;调用当前线程的run()

我们不能通过直接调用run()的方式启动线程

再启动一个线程,不可以还让已经start()的线程去执行.会报Illegalthreadexception,需要重新创建一个线程的对象

创建Thread类的匿名子类的方法

Public class ThreadDemo(){
    
    new Thread(){
        @override
        public void run(){
            
        }
    }.start();
      
    
}

Thread中的常用方法:

  1. start(): 启动当前线程;调用当前线程的run()
  2. run(): 通常需要重写Thread类中的方法,将创建的线程要执行的操作声明在此方法中
  3. currentThread(): 静态方法,返回执行当前代码的线程
  4. getName(): 获取当前线程的名字
  5. setName(): 设置当前线程的名字
  6. yield(): 释放当前CPU的执行权
  7. join(): 在线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行完以后,线程a才结束阻塞状态
  8. stop(): 已过时.强制结束线程生命期
  9. sleep(long millitime): 让当前线程"睡眠"指定的millitime毫秒.在指定的millitime毫秒时间内,当前线程是阻塞状态
  10. isAlive(): 判断当前线程是否存活

方式二:实现Runnalbe接口

  1. 创建一个实现了Runnalbe接口的类
  2. 实现类去实现Runnable中的抽象方法:run()
  3. 创建实现类的对象
  4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
  5. 通过Thread类的对象调用start()-->启动线程;调用当前线程的run():调用了Runnable类型的target的run()方法
class  MThread implements Runnable(){
    @override
    public void run(){
        
      ............
          
    }
}

public class Threadtest{
    public static void main(String[] args){
        MThread mThread = new MThread();
        Thread t1 = new Thread(mThread);
        t1.start();
    }
}


//匿名对象的创建
new Thread(new runnable()){
    @override
    public void run(){
        
    }
}

线程的优先级:

  1. MAX_PRIORITY:10
  2. MIN_PRIORITY:1
  3. NORM_PRIORITY:5 --默认的优先级

如何设置线程的优先级

getPriority():获取线程的优先级

setPriority(int p:)设计线程的优先级

说明:高优先级的线程要抢占低优先级线程cpu的执行权.但是只是从概率上讲,高优先级的线程高概率的情况下被执行,并不意味着只有当高优先级的线程执行完以后,低优先级的线程才执行.

两种创建方式的对比

开发中,优先选择:实现Runnable接口的方式

原因1. 实现的方式没有类的单继承性的局限性

    2. 实现的方式更适合来处理多个线程有共享数据的情况

联系:public class Thread implements Runnable

相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中.

方式三:实现Callable接口 - - JDK 5.0新增

//1.创建一个实现Callable的实现类
class NumThread implements Callable{
    //2.实现call方法,将次线程需要执行的操作声明在call()中
    @override
    public Object call() throws Exception{
        
    }
}

public class ThreadNew{
    NumThread numThread = new NumThread()
        //3.创建Callable接口实现类的对象
    FutreTask futureTask = new FutureTask(numThread);
        //4.将此Callable接口实现类的对象作为传递到FutreTask构造器中,创建FutreTask的对象
    new Thread(futureTask).start();
        //5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()
    try{
        //.6
        //get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值.
        futureTask.get();
        .........
    }catch(InerruptedException e){
    }catch(ExecutionException e){
        
    }
}

问题:如何理解实现Callable接口的方式创建多线程比实现Runable接口创建接口方式强大?

  1. call()可以有返回值的.
  2. call()可以抛出异常,被外面的操作捕获,获取异常的信息
  3. Callable是支持泛型的

方式四:使用线程池

好处:

  1. 提高响应速度(减少了创建新线程的时间)
  2. 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
  3. 便于线程管理

corePoolSize:核心池的大小

maximumPlloSize:最大线程数

keepAliveTime:线程没有任务时最多保持多长时间后会终止

class NumberThread implements Runnable{
    @override
    public void run(){
        
    }
}

class NumberThread1 implements Runnable{
    @override
    public void run(){
        
    }
}


public class ThreadPool{
    public static void main(String[] args){
        //1. 提供指定线程数量的线程池
        ExecutorService service = Executors.newFixedThreadPool(nThread:10);
        ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;
        //设置线程池的属性
        //System.out.println(service.getClass())
        service1.setcorePoolSize(15);
        //service1.setKeepAliveTime();
        //2. 执行指定的线程的操作.需要提供实现Runnable接口或Callable接口实现类的对象
        service.execute(new NumberThread());//适合适用于Runnable
        service.execute(new NumberThread1());
        //ervice.submit(Callable callable);//适合适用于Callable;
        //关闭连接池
        service.shutdown;
    }
}
posted @ 2021-02-06 22:17  伟成李  阅读(45)  评论(0)    收藏  举报