线程及线程池

目录

一、线程与进程

进程:内存中运行的具有独立内存空间的应用程序

线程:是进程的执行路径,共享一个内存空间,线程之间可以自由切换,并发执行,一个进程最少有一个线程

 二、线程调度

分时调度:所有线程轮流使用CPU使用权,平均分配给每个线程占用CPU的时间

抢占式调度:优先让优先级高的线程使用CPU,如果优先级相同,则会随机选择一个(线程随机性)。使用抢占地调度模式再多个线程之间进行高速切换,对于CPU一个核心而言,某一时刻只能执行一个线程,而CPU再多个线程切换速度相比人眼要快很多,所以看起来是在同一时刻运行,所以多线程程序并不能提高运行速度,但是能够提高程序运行效率,提高CPU使用率。

三、同步与异步

同步:排队执行,效率低但是安全

异步:同时执行,效率高但是不安全

四、并发与并行

并发:两个或多个事件在同一时间段内发生

并行:两个或多个事件在同一时刻同时发生

五、java.lang.Thread类

继承Thread

public class Demo1 {
    public static void main(String[] args) {
        Thread1 thread1 = new Thread1();
        thread1.start();
        for(int i=0;i<3;i++){
            System.out.println(i);
        }
    }
}

/**
 * run方法就是线程执行的任务方法
 */
class  Thread1 extends Thread{
    @Override
    public void run() {
        //不是调用run方法,通过Thread对象调用start()来启动
        for(int i=0;i<5;i++){
            System.out.println(i);
        }

    }
}

程序启动运行main时候,java虚拟机启动一个进程,主线程main在main()调用时候被创建。随着调用对象的start方法,另外线程也启动了,这样,整个应用就在多线程下运行。

六、实现java.lang.Runnable接口

/**
 * Runnable和Thread相比:
 * 通过创建任务,给线程分配实现多线程,更适合多个线程同时执行相同任务的情况
 * 避免单继承的局限性
 * 任务与线程分离
 * 线程池接收Runnable类型任务,不接收Thread类型线程
 */
public class Demo1 {
    public static void main(String[] args) {
        //实现Runnable,创建任务对象
        MyRunnable m = new MyRunnable();
        //创建线程分配任务
        Thread r = new Thread(m);
        r.start();
        for(int i=0;i<4;i++){
            System.out.println(i);
        }
    }
}
/**
 * 给线程执行的任务
 */
class MyRunnable implements Runnable{

    @Override
    public void run() {
        for(int i=0;i<5;i++){
            System.out.println(i);
        }
    }
}

MyRunnable类通过实现Runnable接口,使得该类有了多线程类的特征。run()方法是多线程程序的一个约定。所有的多线程代码都在run方法里面, 比较以上两个运行结果得知,多线程程序是乱序执行

七、线程类常见方法

       sleep(): 强迫一个线程睡眠N毫秒。 
  isAlive(): 判断一个线程是否存活。 
  join(): 等待线程终止。 
  activeCount(): 程序中活跃的线程数。 
  enumerate(): 枚举程序中的线程。 
       currentThread(): 得到当前线程。 
  isDaemon(): 一个线程是否为守护线程。 
  setDaemon(): 设置一个线程为守护线程。(用户线程和守护线程的区别在于,是否等待主线程         依赖于主线程结束而结束) 
  setName(): 为线程设置一个名称。 
  wait(): 强迫一个线程等待。 
  notify(): 通知一个线程继续运行。 
  setPriority(): 设置一个线程的优先级

八、线程安全问题

public class Demo1 {
    public static void main(String[] args) {
        Runnable r = new Ticket();
        new Thread(r).start();
        new Thread(r).start();
        new Thread(r).start();

    }
}
class  Ticket implements Runnable{
    //票数
    private int count = 10;
    @Override
    public void run() {
        while(count>0){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            count--;
            System.out.println("余票:"+count);
        }

    }
}

 三个线程执行同一个任务出现的安全问题,票数出现负数情况

九、安全问题解决

线程同步synchronized加锁机制

1、同步代码块

 public void run() {
        synchronized (o) {
            while (count > 0) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count--;
                System.out.println("余票:" + count);
            }

        }
    }

2、同步方法

@Override
    public void run() {
        while (true){
            boolean flag = sale();
            if(!flag){
                break;
            }
        }
        }
    public synchronized boolean sale(){
        while (count > 0) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            count--;
            System.out.println("余票:" + count);
        }
        return true;
    }
}

3、显示锁Lock

class  Ticket implements Runnable {
    //票数
    private int count = 10;
    Lock l = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            if (count > 0) {
                l.lock();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count--;
                System.out.println("余票:" + count);
            }else {
                break;
            }
            l.unlock();
        }
    }
}

10、带返回值的线程Callable使用步骤

1. 编写类实现Callable接口 , 实现call方法
class XXX implements Callable<T> {
@Override
     public <T> call() throws Exception {
       return T;
     }
}
2. 创建FutureTask对象 , 并传入第一步编写的Callable类对象
FutureTask<Integer> future = new FutureTask<>(callable);
3. 通过Thread,启动线程
new Thread(future).start();

11、线程池

1、缓存线程池

/**
  * 缓存线程池.
  * (长度无限制)
  * 执行流程:
  *   1. 判断线程池是否存在空闲线程
  *   2. 存在则使用
  *   3. 不存在,则创建线程 并放入线程池, 然后使用
  */
 ExecutorService service = Executors.newCachedThreadPool();
 //向线程池中 加入 新的任务
 service.execute(new Runnable() {
   @Override
   public void run() {
     System.out.println("线程的名称:"+Thread.currentThread().getName());
   }
 });
 service.execute(new Runnable() {
   @Override
   public void run() {
     System.out.println("线程的名称:"+Thread.currentThread().getName());
   }
 });
 service.execute(new Runnable() {
   @Override
   public void run() {
     System.out.println("线程的名称:"+Thread.currentThread().getName());
   }
 })

2、定长线程池

/**
  * 缓存线程池.
  * (长度无限制)
  * 执行流程:
  *   1. 判断线程池是否存在空闲线程
  *   2. 存在则使用
  *   3. 不存在,则创建线程 并放入线程池, 然后使用
  */
 ExecutorService service = Executors.newCachedThreadPool();
 //向线程池中 加入 新的任务
 service.execute(new Runnable() {
   @Override
   public void run() {
     System.out.println("线程的名称:"+Thread.currentThread().getName());
   }
 });
 service.execute(new Runnable() {
   @Override
   public void run() {
     System.out.println("线程的名称:"+Thread.currentThread().getName());
   }
 });
 service.execute(new Runnable() {
   @Override
   public void run() {
     System.out.println("线程的名称:"+Thread.currentThread().getName());
   }
 })

3、单线程线程池


 /**
  * 单线程线程池.
  * 执行流程:
  *   1. 判断线程池 的那个线程 是否空闲
  *   2. 空闲则使用
  *   4. 不空闲,则等待 池中的单个线程空闲后 使用
  */
 ExecutorService service = Executors.newSingleThreadExecutor();
 service.execute(new Runnable() {
   @Override
   public void run() {
     System.out.println("线程的名称:"+Thread.currentThread().getName());
   }
 });
 service.execute(new Runnable() {
   @Override
   public void run() {
     System.out.println("线程的名称:"+Thread.currentThread().getName());
   }
 });

4、周期性任务定长线程池

public static void main(String[] args) {
 /**
  * 周期任务 定长线程池.
  * 执行流程:
  *   1. 判断线程池是否存在空闲线程
  *   2. 存在则使用
  *   3. 不存在空闲线程,且线程池未满的情况下,则创建线程 并放入线程池, 然后使用
  *   4. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
  *
  * 周期性任务执行时:
  *   定时执行, 当某个时机触发时, 自动执行某任务 .
   */
 ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
 /**
  * 定时执行
  * 参数1.  runnable类型的任务
  * 参数2.  时长数字
  * 参数3.  时长数字的单位
  */
 /*service.schedule(new Runnable() {
   @Override
   public void run() {
     System.out.println("俩人相视一笑~ 嘿嘿嘿");
   }
 },5,TimeUnit.SECONDS);
 */
 /**
  * 周期执行
  * 参数1.  runnable类型的任务
  * 参数2.  时长数字(延迟执行的时长)
  * 参数3.  周期时长(每次执行的间隔时间)
  * 参数4.  时长数字的单位
  */
 service.scheduleAtFixedRate(new Runnable() {
   @Override
   public void run() {
     System.out.println("俩人相视一笑~ 嘿嘿嘿");
   }
 },5,2,TimeUnit.SECONDS);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值