并发编程(1):并发的基本概念、Java创建线程的方式、线程生命周期、线程启动、中断、中断复位。

1、并发中的一些概念。
   qps : 对于单个接口来说,每秒钟能够处理完成的请求次数,注意是处理完成的请求次数,发出请求到服务器处理完成功返回结果。


   tps : 当一次请求包含多个请求的时候,注意是一次请求包含有多个请求,比如请求一个index页面,页面中的数据需要请求多个接
         口,这个时候当所有的请求都收到响应后就表示一个tps,多个qps。


   rt  : 响应时间。


   并发量 :系统能够同时处理的请求数或者事务数。


   系统吞吐量 :系统吞吐量通常由qps(tps)、并发数量两个因素决定。每套系统这两个值都有极限值,只要有一项到达了极限值,系
                统的吞吐量就上不去了,因为如果压力继续增大,系统的吞吐量反而会下降,原因是系统超负荷工作,上下文切换频
                繁、内存消耗等导致系统性能下降。
                
    计算关系
      qps = 并发量/平均响应时间
      


2、什么是并发、并行?
   并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上行。
             所以并发是指在一段时间内宏观上多个程序(或多个线程)同时运行。


   并行:并行(Parallel),当系统有一个以上CPU时,当一个CPU执行一个进程时,另一个CPU可以执行另一个进程,两个进程互抢
         占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。所以并行指的是同一个时刻,多个任务确实真的在同时行。
         
   并发并行的区别
      1、并发,指的是多个事情,在同一时间段内同时发生了,而并行,指的是多个事情,在同一时间点上同时发生了。
      2、并发的多个任务之间是互相抢占资源的,而并行的多个任务之间是不互相抢占资源的。
      3、只有在多CPU的情况中,才会发生并行。否则,看似同时发生的事情,其实都是并发执行的。

      


3、什么是线程?

      线程是cpu的最小调度单元,是用来执行我们的代码编译成的计算机指令的。

 

4、什么是上下文切换?
      当前任务执行一个时间片后会切换到下一个任务。但是,在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以       再加载这个任务的状态。所以任务从保存到再加载的过程就是一次上下文切换。

      
5、java中使用多线程的方式:
   方式1:继承Thread类,重写run方法。

          public class MyThread extends Thread {
             @Override
             public void run() {
               System.out.println("doSomething");
             }
          
             public static void main(String[] args) {
               MyThread myThread = new MyThread();
               myThread.start();
             }
          } 


        
   方式2:实现Runnable接口,重写run方法。可以做到任务跟线程解耦。

           public class MyRunable implements Runnable {
               @Override
               public void run() {
                   System.out.println("doSomething");
               }
           
               public static void main(String[] args) throws InterruptedException {
                   MyRunable task = new MyRunable();
                   Thread t = new Thread(task);
                   t.start();
               }
           } 

 

    方式3:Callable<T>/Future<T>,实现Callable接口,重新call方法,然后使用Future来获取任务执行的返回结果,就是回调。
           

           public class MyCallable implements Callable<String> {
               @Override
               public String call() throws Exception {
                   return "Success";
               }
           
               public static void main(String[] args) throws ExecutionException, 
                                                                InterruptedException {
                   //使用的方式1--使用FutureTask
                   MyCallable myCallable = new MyCallable();
                   FutureTask<String> futureTask = new FutureTask(myCallable);
                   futureTask.run();
                   String result = futureTask.get();
                   System.out.println(result);
                   System.out.println("================================");
                   //使用方式2--使用线程池提交
                   ExecutorService executorService = Executors.newFixedThreadPool(1);
                   Future<String> submit = executorService.submit(myCallable);
                   System.out.println(submit.get());
               }
            }


            
            
6、线程的生命周期:
   Java中线程的生命周期:
   
   

7、线程的启动:
   new Thread().start();原理:调用一个本地 native 方法 start0(),为什么要使用native方法呢?是因为让jvm去调用os操作系统去创建一条线程,然后启动线程。
   
   start() 与run方法的区别:
   new Thread().start() 表示使用当前线程执行任务。
   new Thread().run() 表示调用使用主线程调用当前线程实例的run方法,并不是使用创建的线程来执行任务。
   


8、线程的终止:
   Thread t = new Thread();
   方式1、t.stop()方法:不建议使用,强制终止当前线程,可能会带来数据不完整的问题,比较暴力。
   方式2、t.interrupt()发送终止通知:需要配合中断标记boolean isInterrupted = t.isInterrupted()使用默认值是false,当调用                         t.interrupt()会将此值设置为true。
          案例如下:
          案例:使用线程的isInterrupted标记来做逻辑控制来实现线程的终止。
               

                public class InterruptDemo0 implements Runnable {
                     @Override
                     public void run() {
                         while(!Thread.currentThread().isInterrupted()){
                             System.out.println("runing ...");
                         }
                         System.out.println("stop ...");
                     }
                 
                     public static void main(String[] args) throws InterruptedException {
                         Thread t = new Thread(new InterruptDemo0(),"thread001");
                         t.start();
                         //输出t线程是否为中断,默认为false,其实就是线程维护了一个中断标记,此标 
                           记默认为false
                         System.out.println(t.isInterrupted());
                         //保证t线程执行到睡眠的时候。
                         Thread.sleep(1000);
                 
                         //让t线程处于中断状态,就是将线程维护的中断标记设置为true
                         t.interrupt();
                     }
                 }

        #1  中断复位:在调用线程t.interrupt()方法的时候,如果当前线程处于等待状态中,
                      比如调如下方法都会让线程处于WAITING或TIME_WAITING状态中。
                         Thread.sleep(100000);
                         InterruptDemo1.class.wait();    
                         Thread.currentThread().join(); 等需要处理InterruptedException的方法。

                         在调用这些方法到时候都要捕获InterruptedException,在捕获这个异常的时候会触发线程的复位,也就是会将当                          前线程的中断标记恢复到默认的false值。那么问题来了,为什么要复位呢?说白了就是把后续的决定权交到开发者手                        上,开发者可以在catch里面添加处理,如果开发者就要终止此线程那就再次调Thread.currentThread().interrupt()线                        程的终止方法,这个时候就能到达终止线程的目的。如果开发者不想终止线程那就什么都不做。


                      举个例子来形容这个问题:比如你在睡午觉,有个人突然叫醒你,是继续睡还是起来干活完全由你决定,如果你决定                         要起来干活了,你就中断当前的睡觉。    

        #2  手动复位我们可以手动调用Thread.interrupted()静态方法来复位当前线程,也就是手动手动将当前线程的中断标记设置                                 为默认的false值。

          复位案例:
                 

                   public class InterruptDemo1 implements Runnable {
                       @Override
                       public void run() {
                           while(!Thread.currentThread().isInterrupted()){
                               try {
                                   //当前线程沉睡200秒
                                   TimeUnit.SECONDS.sleep(200);
                               } catch (InterruptedException e) {//捕获这个异常的时候会触发线程的复位,也就是会将当前线程的中断标记                                恢复到默认的false值。    
                                   //二次中断以终止当前线程。
                                   Thread.currentThread().interrupt();
                               }
                           }
                           System.out.println("线程结束。。。");
                       }
                   
                       public static void main(String[] args) throws InterruptedException {
                   
                           Thread t = new Thread(new InterruptDemo1(),"thread001");
                           t.start();
                   
                           //输出t线程是否为中断,默认为false,其实就是线程维护了一个中断标记,此标记默认为false
                           System.out.println(t.isInterrupted());
                   
                           //保证t线程执行到睡眠的时候。
                           Thread.sleep(1000);
                   
                           //让t线程处于中断状态,就是将线程维护的中断标记设置为true
                           t.interrupt();
                   
                           //Thread.interrupted();//手动复位当前线程。
                       }
                   }


                   
        #3  interrupt()方法原理调用线程的interrupt()方法最终也会调用到一个native方法,其实就是使用jvm层面来做处理,jvm是使用c++来编写的,线程的中断标记就是在jvm层面维护的。               

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值