zoukankan      html  css  js  c++  java
  • Java线程的相关问题

    一、创建线程方式

    a.       继承线程类( new Thread),重写run方法;

    代码实例
    public class MyThread extends Thread{//继承Thread类
      public void run(){
      //重写run方法
      }
    }
    public class Main {
       public static void main(String[] args){
        new MyThread().start();//创建并启动线程
      }
    }

    b.       实现runnable接口,将runnable对象传入Thread类;

    代码实例:
    public class MyThread2 implements Runnable {//实现Runnable接口
      public void run(){
      //重写run方法
      }
    }
    public class Main {
      public static void main(String[] args){
        //创建并启动线程
        MyThread2 myThread=new MyThread2();
        Thread thread=new Thread(myThread);
        thread().start();
        //或者    new Thread(new MyThread2()).start();
      }
    }

    c.        使用线程池的方式,提交runnable或callable任务;

    代码实例:
    public class Main {
      public static void main(String[] args){
       MyThread3 th=new MyThread3();
       //使用Lambda表达式创建Callable对象
         //使用FutureTask类来包装Callable对象
       FutureTask<Integer> future=new FutureTask<Integer>(
        (Callable<Integer>)()->{
          return 5;
        }
        );
       new Thread(task,"有返回值的线程").start();//实质上还是以Callable对象来创建并启动线程
        try{
        System.out.println("子线程的返回值:"+future.get());//get()方法会阻塞,直到子线程执行结束才返回
        }catch(Exception e){
        ex.printStackTrace();
       }
      }
    }

    d.       推荐使用第三种方式。高效,资源可控;

    二、什么是线程同步?线程同步什么时候用?

    1)什么是线程同步;

    即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态;

    2)线程同步在什么时候用(卖火车票,飞机票,取钱);

    简单的说,同步就是防止多个线程访问同一个对象,造成数据不安全;线程的同步意味安全,譬如你去取钱 ,你的执行语句和我用的要是相同对象 ,你要在卡上扣除的钱数和银行卡里面要有这么多钱才能扣除;

    三、什么是线程安全;

    1)所谓线程安全,是多个线程并发执行的情况下结果总是跟单线程运行的结果一致,逻辑上不会出现错误;

    2)什么情况下会出现线程安全问题?

    多个线程同时操作同一份数据,常常会导致线程安全问题。比如:全局的变量,静态变量,同一条数据的数据库操作等;

    局部变量,通常不会存在线程安全问题。

    3)常见的解决线程安全的方式:

       1)避免使用全局的变量,将全局的变量定义为局部变量。

       2)加同步锁,使得线程同步。

               a.        Synchronized 同步关键字,可以加在方法和代码块上面;  

    /**
         * synchronized添加到方法上面,使方法变成同步方法
         * 如果是静态方法,锁住的是class
         * 如果是普通方法,锁住的this,当前对象 synchronized(this)
         * 多个线程锁住的对象是同一个对象才能够同步,每个类都有当前对象
         */
    
        public static synchronized void salTicket(){
            if (ticketNum > 0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "买到第" + ticketNum-- + "张票");
                System.out.println(Thread.currentThread().getName() + "买票完成");
            }else {
                System.out.println("票已经售完,"+Thread.currentThread().getName() + "未买到票");
            }
        }

               b.       多个线程方法是否同步,需要判断多个线程是否共用同一把锁;

    /**
         * 同步代码块
         */
        public void salTicket2() {
            synchronized (this) {
                //()中指定锁对象,this表示当前对象,多个线程使用同一个对象调用该方法时,是同步的
                //如果指定为 class,则该类的任意对象调用该方法都是同步的
                if (ticketNum > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "买到第" + ticketNum-- + "张票");
                    System.out.println(Thread.currentThread().getName() + "买票完成");
                } else {
                    System.out.println("票已经售完," + Thread.currentThread().getName() + "未买到票");
                }
            }
        }

               c.        ReentrantLock 对象的lock 方法进行加锁,unLock进行解锁。Unlock必须放在finally中。确保能够最终释放锁;

     //锁对象
    private static ReentrantLock lock=new ReentrantLock();
     /**
         * 使用lock对象进行同步,多个线程使用的是同一个lock对象,才会是同步的
         */
        public void salTicket3() {
            lock.lock();//加锁
                if (ticketNum > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        lock.unlock();//释放锁,必须放在finally代码块中,以确保能够释放锁
                    }
                    System.out.println(Thread.currentThread().getName() + "买到第" + ticketNum-- + "张票");
                    System.out.println(Thread.currentThread().getName() + "买票完成");
                } else {
                    System.out.println("票已经售完," + Thread.currentThread().getName() + "未买到票");
                }
        }

        3)数据库操作的话,也可以使用乐观锁或悲观锁的方式

    4)Springmvc是如何解决线程安全问题的?

    Springmvc的数据接收和传递都是方法级别的,使用局部变量来接收和传递,所以不存在线程安全问题。

    四、Wait 和notify

       线程间通讯的一种机制。用于手动控制线程之间的切换。在同步代码中的锁对象调用。可以同时通过共享内存对象,来实现数据的传递;

       Wait 使线程进入阻塞状态,并释放锁资源;

       Notify 随机唤醒一个因wait进入阻塞状态的线程;

       NotifyALL  唤醒所有的因wait进入阻塞状态的线程;

    3)多线程实现,怎么用?

    a、将单个大的任务拆分成多个小任务,使用多线程去执行;

      多线程的效率不一定比单线程的效率高;

      通过线程池创建线程,通过实现runnable(无返回值)或callable(有返回值)接口来定义任务;

      通过线程池的submit  invoke invokeAll 等方法来执行任务;

    b、使用线程异步完成某些任务,提高并发响应的能力,或让线程周期性的执行某些任务;

    c、四种线程池的特点及其创建;

    Java通过Executors提供四种线程池,分别为:

    1)newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

    2)newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

    3)newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

    4)newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

    //jdk中提供的四种快速创建线程池的方式
            //1.定长线程池
            ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);
            //2.缓存线程池
            ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
            //3.周期线程池,可用来实现定时任务
            ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
            //4.单线程线程池
            ExecutorService executorService = Executors.newSingleThreadExecutor();
  • 相关阅读:
    面试题系列--【vue的生命周期】
    面试题系列--【hash和history的区别】
    ES6系列--【事件循环 EventLoop(Promise,setTimeOut,async/await执行顺序)】
    ES6系列--【ES6数组新增方法】
    ES6系列--【ES6 新增字符串方法】
    微信小程序系列--【VXML语法、VMSS样式、条件渲染、列表渲染、模板、引用、组件、事件系统】
    微信小程序系列--【小程序注册、工程创建、全局配置、页面配置】
    微信小程序系列---【五星好评案例】
    react系列---【Hooks】
    2019.9.18-单向循环链表删除元素(+之前完整代码)
  • 原文地址:https://www.cnblogs.com/xie-qi/p/13205639.html
Copyright © 2011-2022 走看看