线程的基本认识与创建

多线程

1、进程和线程的认识

 * 1)进程指的一段正在运行的程序
 * 一个程序运行中可以执行过个任务,任务称之为线程
 * 2)进程是程序执行过程中资源分配和管理的基本单位
 *    线程是cpu执行的最小单位
 * 进程拥有自己的独立的地址空间,每启动一个进程,系统就会分配地址空间
 * 进程可以拥有多个线程,各个线程之间共享程序的内存空间
 * 为什么出现线程?
 * 每个进程有自己独立的地址空间,多并发请求,为每一个请求创建一个进程
 * 导致系统开销、用户请求效率低
 *
 * 串行 -》 批处理 -》进程 -》线程
 * 面试题:多线程和多进程有哪些区别?
 * 1)每个进程拥有自己独有的数据,线程共享数据
 *    线程之间的通信相比于进程之间的通信更有效 更容易
 * 2)线程相比于进程创建/销毁开销 更小
 * 3)进程是资源分配的最小单位,线程是cpu调度的最小单位
 * 4)多进程程序更加健壮,多线程程序只要有一个线程挂掉,对其共享资源的
 * 其他线程也会产生影响
 * 5)如果追求速度,选择线程
 *    如果频繁创建和销毁,选择线程
 *    如果追求系统更加稳定,选择进程
 * 线程是轻量级的进程
 *
 * JVM-》一个进程
 * 2、线程的创建
 * 1)继承Thread类,重写run()方法 边吃饭边看电视
 * 2)实现Runnable接口,重写run方法
 * 3)匿名线程 匿名内部类
 * 4) 实现Callable接口,重写call方法
 * Callable接口存在Executor框架中类,相比于Runnable更加强大
 * a.Callable可以在任务执行结束之后提供一个返回值
 * b.call方法可以抛出异常
 * c.运行Callable任务可以拿到一个Future对象,Future提供get方法
 * 拿到返回值(异步)
 *
 * 通过Callable和FutureTask创建线程:
 * a.创建Callable接口的实现类,重写call方法
 * b.创建Callable实现类的实例,使用FutureTask包装该实例
 * c.将FutureTask实例作为参数创建线程对象
 * d.启动该线程
 * e.调用FutureTask的get方法获取子线程的执行结果
 * 面试题:Callable和Runnable接口的区别:
 * 1)直观上
 * 2)使用上
 * 3)使用场景
 *

1)继承Thread类,重写run()方法 边吃饭边看电视

    class MyThread extends Thread{
    
    
        @Override
        public void run() {
    
    
            //线程执行体
            while(true){
    
     //1
                System.out.println("eat food");//2
            }
        }
    }
     public  void main(String[] args) {
    
    
        //main线程
        while(true){
    
    
            System.out.println("watch TV"); //3
        }
        //extends Thread创建子线程
        //创建子线程对象
        Thread thread = new MyThread(); //1
        //启动吃饭的thread
        thread.start(); //start -> run //2
        }

2)实现Runnable接口,重写run方法

    class MyRunnable implements Runnable{
    
    

        @Override
        public void run() {
    
    
            //线程执行体
            while(true){
    
     //1
                System.out.println("eat food");//2
            }
        }
    }
    public  void main(String[] args) {
    
    
        //main线程
        while(true){
    
    
            System.out.println("watch TV"); //3
        }
            //implements Runnable创建子线程
        //创建子线程对象,将Runnable实例作为参数实例化子线程对象
        Thread thread = new Thread(new MyRunnable());
        //启动吃饭的thread
        thread.start();
        }

3)匿名线程 匿名内部类

     public  void main(String[] args) {
    
    
        new Thread(){
    
    
            @Override
            public void run() {
    
    
                System.out.println("thread-0");
            }
        }.start();
    }

4) 通过Callable和FutureTask创建线程:
* a.创建Callable接口的实现类,重写call方法
* b.创建Callable实现类的实例,使用FutureTask包装该实例
* c.将FutureTask实例作为参数创建线程对象
* d.启动该线程
* e.调用FutureTask的get方法获取子线程的执行结果

    class MyCallable implements Callable<Integer> {
    
    
        @Override
        public Integer call() throws Exception {
    
    
            int sum = 0;
            for(int i=0; i<10000; i++){
    
    
                sum += i;
            }
            return sum;
        }
    }
     public  void main(String[] args) {
    
    
        Callable<Integer> callableTask = new MyCallable();
        FutureTask<Integer> task = new FutureTask<>(callableTask);
        Thread thread = new Thread(task);
        thread.start();

        //接受线程执行之后的结果
        try {
    
    
            Integer integer = task.get();
            System.out.println("result: "+integer);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        } catch (ExecutionException e) {
    
    
            e.printStackTrace();
        }

start方法剖析

 public synchronized void start() {
    
    
      if(threadStatus!=0)//判断当前线程状态是否为0
            throw new IllegalThreadStateException();
      group.add(this); //当前线程加入一个线程
      boolean started=false;
      try{
    
    
          start0(); //start0是一个native本地方法 调用run执行该线程
          started=true;
      }finally{
    
    
          try{
    
    
            if(!started){
    
    
                group.threadStartFailed(this);
            }
          }catch(Throwable ignore){
    
    
      }
  }

start方法首先将线程加入一个线程组中,这时该线程进入Runnable就绪状态,start0
获取cpu资源执行程序自定义的run方法

run方法就是一个普通的方法,不会启动一个新的线程

注意:线程在调用start方法的时候会有一个threadStatus,如果不等于0说明已经
启动,不能够重复启动,重复启动抛异常IllegalThreadStateException
*/

多线程实现一个叫号服务器

在这里插入图片描述

class TicketSystem extends Thread{
    
    
    private String name;
    private static final int max = 200; //最多叫到50号
    private static int index = 1; //当前叫号值

    public TicketSystem(String name){
    
    
        this.name = name;
    }

    @Override
    public void run() {
    
    
        while(index <= max){
    
    
            System.out.println("当前办理业务为:"+name+", 当前号码为:"+index++);
        }
    }
}

class TicketSystemTask implements Runnable{
    
    
    private static final int max = 200; //最多叫到50号
    private static int index = 1; //当前叫号值


    @Override
    public void run() {
    
    
        while(index <= max){
    
    
            System.out.println("当前办理业务为:"+Thread.currentThread().getName()+", 当前号码为:"+index++);
        }
    }
}
public class TestDemo2 {
    
    
    public static void main(String[] args) {
    
    
        TicketSystemTask task = new TicketSystemTask();
        Thread t1 = new Thread(task, "1号柜台");
        Thread t2 = new Thread(task, "2号柜台");
        Thread t3 = new Thread(task, "3号柜台");
        Thread t4 = new Thread(task, "4号柜台");
        Thread t5 = new Thread(task, "5号柜台");
        t1.start();
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
//        TicketSystem t1 = new TicketSystem("1号柜台");
//        t1.start();
//
//        TicketSystem t2 = new TicketSystem("2号柜台");
//        t2.start();
//
//        TicketSystem t3 = new TicketSystem("3号柜台");
//        t3.start();
//
//        TicketSystem t4 = new TicketSystem("4号柜台");
//        t4.start();
//
//        TicketSystem t5 = new TicketSystem("5号柜台");
//        t5.start();
    }

猜你喜欢

转载自blog.csdn.net/weixin_47198561/article/details/113523544