1. 多线程

    多线程是为了提高资源利用率,在‘同一个程序(进程)’内部,并发执行多个‘任务(代码路径)’的技术。

    并发: 同一时刻,多个指令在单个CPU上交替执行

    并行: 同一时刻,多个CPU同时执行多个指令

  2. 多线程的实现方式:

    通过继承Thread,重写run方法来实现

    public static void main(String[] args) {
    
        MyThread myThread=new MyThread();
        MyThread myThread1=new MyThread();
        myThread1.setName("Rance1");
        myThread.setName("Rance2");
        myThread1.start();
        myThread.start();
    
    }
    
    static class MyThread extends Thread{
        @Override
        public void run(){
            String name=getName();
            for (int i = 0; i < 100; i++) {
            System.out.println(name+": RanceXXX");
            
            //出让线程,表示让出当前CPU的执行权
            Thread.yield();
            }
        }
    }

  3. 通过实现Runnable接口,重写run方法来实现
  4. 为了获取到线程的返回值,通过实现Callable接口,重写call方法,用FutureTask来管理线程的返回值
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建MyCallable对象
        MyCallable mc=new MyCallable();
        //创建Future实现类FutureTask来管理MyCallable的结果
        FutureTask<Integer> ft=new FutureTask<>(mc);
        //创建线程,传入ft参数
        Thread thread=new Thread(ft);
        thread.start();
    
        Integer i = ft.get();
        System.out.println(i);
        
        //插入线程,使thread线程运行在main线程(当前线程)的前面
        t.join();
        fori.10.sout....
    
    }
    public class MyCallable implements Callable<Integer> {//泛型为返回值类型
        @Override
        public Integer call() throws Exception {
            int sum=0;
            for (int i = 1; i <= 100; i++) {
                sum = i + sum;
            }
            return sum;
        }
    }

  1. Thread常见的成员方法:

  2. main线程负责main方法中的代码的执行

    使用sleep方法进行线程的休眠,哪个线程执行到了这个方法,那么就进行休眠,单位为ms

    java中的CPU调度使用的是抢占式调度,然后的话,可以通过setPriority设置优先级,优先级越高,越可能抢到CPU,主打随机性

  3. 守护线程,如果非守护线程还没有结束,那么大家都正常运行,如果非守护线程都结束了,那么就会陆续结束守护线程

  4. <<时间之外的往事(计算机操作系统的事情)>> 1.

  5. 多线程中的不安全性(线程在执行的过程中随时可能会失去CPU的执行权)

    1. 重复票是怎么回事
    2. 票超出了是怎么回事
  6. 使用同步代码块解决多线程不安全的问题:

    public class MyThread extends Thread {
    
      public static int ticket = 0;
      
      @Override
      public void run() {
          while (true) {//同步synchronized一定要写在while里面,然后锁一定要是唯一的一个对象,MyThread.class表示的是MyThread的字节码文件
              synchronized (MyThread.class) {
                  if (ticket < 100) {
                      System.out.println(getName() + ":正在卖第" + ticket + "张票");
                      ticket++;
                  } else {
                      break;
                  }
              }
          }
      }
    }

  7. 同步方法,在方法前加入synchronized关键字

    @Override
    public void run() {
        while (true) {
            if (extracted()) break;
        }
    }
    
    private synchronized boolean extracted() {
        if (ticket < 100) {
            System.out.println(getName() + ":正在卖第" + ticket + "张票");
            ticket++;
        } else {
            return true;
        }
        return false;
    }

  8. Lock手动上锁开锁的操作:

    public class MyThread extends Thread {
    
    	public static int ticket = 0;
    	
    	static Lock lock=new ReentrantLock();
    
    
    	@Override
    	public void run() {
    	    while (true) {
    	        lock.lock();
    	        try {
    	            if (ticket < 100) {
    	                System.out.println(getName() + ":正在卖第" + ticket + "张票");
    	                ticket++;
    	            } else {
    	                break;
    	            }
    	        } catch (Exception e) {
    	            throw new RuntimeException(e);
    	        } finally {
    	            lock.unlock();
    	        }
    	    }
    	}
    
    }
    

  9. 死锁,锁的嵌套:

  10. <<时间之外的往事(操作系统相关之pv操作)>>

    1. 生产者和消费者模型

    b.生产者和消费者模型的代码实现:

  11. 阻塞队列实现生产者消费者模型

    public class Cook extends Thread{
    
      ArrayBlockingQueue<String> arrayBlockingQueue;
    
    
      public Cook(ArrayBlockingQueue<String> arrayBlockingQueue) {
          this.arrayBlockingQueue = arrayBlockingQueue;
      }
    
    
      @Override
      public void run(){
          while(true){
              try {
                  arrayBlockingQueue.put("面条");
    
                  System.out.println("厨师做了一碗面");
    
              } catch (InterruptedException e) {
                  throw new RuntimeException(e);
              }
          }
      }
    
    }
  12. 抢红包的逻辑:

    public class People extends Thread {
    
      static double redEnvelope = 100;
    
      static int count = 3;
    
      static final double MIN=0.01;
      @Override
      public void run() {
          synchronized (People.class) {
              if(count==0){
                  System.out.println(Thread.currentThread().getName()+"没抢到红包!!!");
              }else{
                  Random r=new Random();
                  //用来表示中奖金额
                  double prize=0;
                  if(count==1){
                      prize=redEnvelope;
                  }
                  else{
                      double ram=redEnvelope-(count-1)*MIN;
                      prize = ((prize = r.nextDouble(ram)) < MIN) ? MIN: prize;
                  }
                  System.out.println(Thread.currentThread().getName()+"抢到了"+prize+"元红包!!!");
                  redEnvelope-=prize;
                  count--;
              }
    
          }
    
      }
    }

  13. 抽奖箱逻辑:

    public class LotteryPool extends Thread{
    
        static ArrayList<Integer> list=new ArrayList<>();
        static {
            Collections.addAll(list,10,2,5,20,100,50,200,500,800,80,300,700);
        }
        @Override
        public void run(){
            while(true){
                synchronized (LotteryPool.class){
                    if(list.isEmpty()){
                        break;
                    }
                    else{
                        Collections.shuffle(list);
                        Integer remove = list.removeFirst();
                        System.out.println(Thread.currentThread().getName()+"又产生了一个"+remove+"元大奖");
                    }
                }
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

  14. 线程栈是不唯一的,每个线程有自己的栈,堆内存是唯一的

    1. 这个图表示main线程栈读取main方法,main方法进栈,然后,创建了两个线程对象,在堆中开辟内存空间,然后当执行start方法时,就会开启线程1和线程2自己的栈,run方法进栈.
  15. 抽奖箱最终版:

    public class LotteryPool implements Callable<Integer> {
    
        static ArrayList<Integer> list=new ArrayList<>();
    
    
        static {
            Collections.addAll(list,10,2,5,20,100,50,200,500,800,80,300,700);
        }
    
    
        @Override
        public Integer call() throws Exception {
            ArrayList<Integer> boxList=new ArrayList<>();
            while(true){
                synchronized (LotteryPool.class){
                    if(list.isEmpty()){
                        System.out.println(Thread.currentThread().getName()+" "+boxList);
                        break;
                    }
                    else{
                        Collections.shuffle(list);
                        Integer remove = list.removeFirst();
                        boxList.add(remove);
                    }
                }
                    Thread.sleep(10);
            }
            if(boxList.isEmpty()) return null;
            else return Collections.max(boxList);
        }
    }
    
    
    public class Test {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
    
            LotteryPool lotteryPool=new LotteryPool();
    
            FutureTask<Integer> ft1=new FutureTask<>(lotteryPool);
            FutureTask<Integer> ft2=new FutureTask<>(lotteryPool);
    
            Thread t1=new Thread(ft1);
            Thread t2=new Thread(ft2);
    
            t1.setName("线程1");
            t2.setName("线程2");
    
            t1.start();
            t2.start();
    
            Integer i1 = ft1.get();
            Integer i2 = ft2.get();
    
            System.out.println(i1+"  "+i2);
    
        }
    }
    

  16. 线程池

    1. 原理:

    2. 代码实现:

      public class Test {
          public static void main(String[] args) {
      //       ExecutorService pool = Executors.newCachedThreadPool();
             MyRunnable myRunnable=new MyRunnable();
      //       pool.submit(myRunnable);
      
              ExecutorService executorService = Executors.newFixedThreadPool(3);
              executorService.submit(myRunnable);
              executorService.submit(myRunnable);
              executorService.submit(myRunnable);
              executorService.submit(myRunnable);
              executorService.submit(myRunnable);
      
          }
      }
      

  17. 自定义线程池:

    1. 来了8个任务,线程池先创建3个核心线程来完成三个任务,然后长度为3,把任务4,5,6进入阻塞队列排队,任务7和8使用临时线程来进行操作

new ThreadPoolExecutor(
	3,//核心线程数量
	6,//总线程数量
  60,//空闲清理线程时间
  TimeUnit.SECONDS,//清理时间的单位
  new ArrayBlockingQueue<>(3),//排队的队伍长度
  Executors.defaultThreadFactory(),//线程从哪里来
  new ThreadPoolExecutor.AbortPolicy()
);

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐