zoukankan      html  css  js  c++  java
  • 涉猎---Java多线程

    在Java程序设计语言中,并发程序主要集中于线程

    而且随着计算机系统拥有多个处理器或带有多个执行内核,线程的系统能力得到了很大的增强

    其中并发程序设计是指由若干个可在同一时间段执行的程序模块组成程序的程序设计方法。

    这种可并发执行的程序模块称为进程,进程由数据和机器指令和堆栈组成,存储在磁盘的程序运行起来就是一个进程,进程在内存中,所以在一个操作系统中能开启的进程是有限的

    线程

    有时被称为轻量进程,它是进程中的一个独立运行单位,是程序执行流的最小单位。

    线程自己不拥有系统资源,只拥有在运行中必不可少的资源,一个线程可以创建和撤销另一个线程,同一个进程中多个线程之间可以并发执行。

    由于线程之间的相互制约,可以说线程有暂停,等待,休眠,停止等状态,从你创建一个线程,到执行任务完毕,这是线程的一个生命周期。

    线程在CPU上执行,(CPU多少核多少线程,简单来说意味着在这台电脑上同一时间能执行多少个线程),线程执行需要消耗CPU(运行),高速缓存(缓存线程运行时所需的数据),内存(存储数据),CPU的读取速度是最快的,为达到最大效率,将数据提前提取到高速缓存中便于CPU在运行时能尽量体现其高速的特性。

    多线程

    线程是程序中一个单一的顺序控制流程,在耽搁程序中同时运行多个线程完成不同的工作,即为多线程,引入线程是因为创建一个新线程花费时间少,两个线程(在同一进程中的)的切换时间少,线程之间互相通信不必调用内核,线程能独立执行;而使用多线程就是最大限度的利用硬件资源来提升程序的效率,(这也就是说在一个进程中不能开启N个线程,因为硬件资源会限制执行效率)。

    Java实现多线程有两种方式

    1.Runnable接口:此接口中有一个run()方法,是线程的运行方法(线程要执行的任务),当run结束时,线程也就结束了;
    2.Thread类:(Thread类是Runnable接口的子类)所以run方法仍然保持,此外这个类中还有start( );和sleep(long time); start方法是线程的启动方法,如果想要JVM把你的这个类当作一个线程,就要使用start方法来启动线程,sleep是线程的休眠方法,单位是毫秒

    新线程态(New Thread) 可运行态(Runnable)
    非运行态(Not Runnable) 死亡态(Dead)
    /*
     * Runnable 是接口 其内部有run()方法
     * Thread 是类  继承了Runnable的接口
     */
    public class Test{ //implements Runnable{ // extends Thread{
     
     public int num;
     
     public Test(int num){
      this.num = num;
     }
     
     public void print() {
      num++;
      System.out.println(Thread.currentThread()+" "+"num ="+num);
     }
     
    }
    
    
    public class ThreadTest extends Thread{
     
     public Test test;
    
    public ThreadTest(Test test) {
      this.test = test;
     }
     
     public void run() {
      while(test.num<20) {
      test.print();
      //异常事件处理
      try {
      //设置休眠时间,以免太快而无法观察
       Thread.sleep(2000);
      } catch (InterruptedException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
        }
       }
     }
     
     public static void main(String[] args) {
      // TODO Auto-generated method stub
      Test tes = new Test(1);
      //启动多线程
      for(int i=0;i<=10;i++) {
      ThreadTest thr = new ThreadTest(tes);
      //构造方法转换thr对象类型
      Thread t = new Thread(thr);
      t.start();
      }
      //输出当前的线程
      System.out.println(Thread.currentThread());
     }
    }
    
    
    Thread[Thread-1,5,main] num =2
    Thread[Thread-13,5,main] num =3
    Thread[Thread-9,5,main] num =4
    Thread[Thread-11,5,main] num =5
    Thread[main,5,main]
    Thread[Thread-7,5,main] num =6
    Thread[Thread-3,5,main] num =7
    Thread[Thread-5,5,main] num =8
    Thread[Thread-21,5,main] num =9
    Thread[Thread-19,5,main] num =10
    Thread[Thread-15,5,main] num =11
    Thread[Thread-17,5,main] num =12
    Thread[Thread-7,5,main] num =13
    Thread[Thread-5,5,main] num =14
    Thread[Thread-15,5,main] num =15
    Thread[Thread-11,5,main] num =16
    Thread[Thread-13,5,main] num =17
    Thread[Thread-1,5,main] num =18
    Thread[Thread-21,5,main] num =19
    Thread[Thread-19,5,main] num =20
    Thread[Thread-17,5,main] num =21
    Thread[Thread-3,5,main] num =22
    Thread[Thread-9,5,main] num =23
    //在这里发现运行结果并非全部的num都变成了20,这就是多线程控制同一变量变化时出现的问题
    

    出现了问题,下边就来解决:
    共用代码块是我想到的第一种方法,代码如下:

    public class Test{ //implements Runnable{ // extends Thread{
     
     public int num;
     
     public Test(int num){
      this.num = num;
     }
     
     public synchronized void print() {
      num++;
      System.out.println(Thread.currentThread()+" "+"num ="+num);
     }
     
    }
    
    
    public class ThreadTest extends Thread{
     
     public Test test;
     //为解决多线程控制同一变量时的问题
     public Object obj = new Object();
     
     public ThreadTest(Test test) {
      this.test = test;
     }
     
     public void run() {
      synchronized(obj) {//共用代码块
      while(test.num<20) {
      test.print();
      try {
       Thread.sleep(2000);
      } catch (InterruptedException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
        }
       }
      }
     }
     
     public static void main(String[] args) {
      // TODO Auto-generated method stub
      Test tes = new Test(1);
      for(int i=0;i<=10;i++) {
      ThreadTest thr = new ThreadTest(tes);
      Thread t = new Thread(thr);
      t.start();
      }
      System.out.println(Thread.currentThread());
     }
    }
    
    

    但貌似并没有起到预想的效果,再接再厉…

    之后在实现界面上直线等的动画时再次见到了多线程,这次与之不同的是,我在网上查找到了多线程怎么控制并发数,有两种方法,第一种是用join方法,第二种则是利用线程池

    过了好久终于解决了~~~~~

    首先明白一个问题,创建一个线程的时间远远小于启动一个线程去运行的时间,所以应该将创建和启动线程分开写

    for(int i=0;i<=10;i++) {
    			ThreadTest thr = new ThreadTest(tes);
    			list.add(thr);
    		}
    		
    		for(ThreadTest tt : list) {
    			tt.start();
    		}
    

    第二点,自加时间足够短,加休眠有点多此一举了,所以run方法就只剩下了一行代码

    test.print();
    

    最终的运行结构发现终于没有重复的值了

    面对一个问题的时候,从问题的本质入手,简单代码上手,理解多线程同步是一个巨大的工程:

    顺便列举一下了解到的多线程同步的七种方法吧

    1. 同步方法
    2. 同步代码块(此上两种方法都是涉及到synchronized关键字的)
    3. wait与notify
    4. 使用特殊域变量(volatile)实现
    5. 重入锁()java.util.concurrennt包
    6. 使用局部变量
    7. 使用阻塞队列实现原子操作
    让对手感动,让对手恐惧
  • 相关阅读:
    mysql 模糊查询LIKE 在tp中使用
    json字符串与 js对象互相转换
    1431. Kids With the Greatest Number of Candies
    1481. Least Number of Unique Integers after K Removals
    560. Subarray Sum Equals K
    1476. Subrectangle Queries
    1475. Final Prices With a Special Discount in a Shop
    网速和流量有什么关系
    计算网速的计算公式是什么
    php file_put_contents 函数的使用
  • 原文地址:https://www.cnblogs.com/RokoBasilisk/p/11780378.html
Copyright © 2011-2022 走看看