zoukankan      html  css  js  c++  java
  • JAVA多线程总结01

     

    一:概述:

      1.1什么是进程,什么是线程:

        进程是一个应用程序,线程是一个应用单元。eg:现在java的dos命令里面最起码有main线程和垃圾回收线程

      1.2进程和线程的关系:

        进程A和进程B内存空间独立不共享,线程A和线程B堆内存和方法区内存共存,但是栈内存,一个线程一个栈。(堆和方法区共享,栈内存独立)

     

    二:实现线程的方法:

      第一种:编写一个新类,直接继承java.lang.thread;并且重写run方法

     

    public class Yunxing2 {
        public static void main(String[] args) {
        MyThread myThread = new MyThread();//新建线程
        myThread.start();//启动新线程
        //作用:启动一个分支线程,在JVM中开辟一个新的栈空间,任务完成后,瞬间就结束了
        //启动成功后,自动调用run方法,并且run方法跟main方法一样在栈空间的底部,同级别的
        //这里的代码还是运行在主线中
        myThread.run();//不用这个
        //作用L不会启动线程,不会分配新的分支栈中,是单线程的run()方法
            for(int i=0;i<1000;i++){
                System.out.println("逐鹿线---->"+i);
            }
        }
    }
    //继承+重写run方法,main中new出一个该类,然后使用start启动一个新的线程
    class MyThread extends Thread{//定义线程类
        @Override
        public void run() {
            //编写程序,这段程序运行在分支线程中(分支)
            for(int i=0;i<1000;i++) {
                System.out.println("分支线程---->"+i);
            }
        }
    }

     

    第二种方法:编写一个类,实现java.lang.Runnable 接口(这种方法更好,因为一个类实现了一个接口,还可以继承别的类)

    //定义一个可运行的类
    public class MyRunnable implements Runnable{
        public void run();
    }
    //创建一个线程对象Thread,并且传一个runnable参数
    Thread t= new Thread(new MyRunnable());
    //启动线程
    t.start();

     

    第三种方法:匿名内部类直接编写分支线程代码:

    //main函数中直接写就好
    Thread t=new Thread(new Runnable(){//在这里直接实现,这就是匿名内部类
        @Override
        public void run(){
            for(int i=0;i<100;i++){
                System.out.println("t线程---->"+i);
            }
        }
    });
    t.start();//启动支线线程
    for(int i=0;i<100;i++){
        System.out.printn("main线程--->"+i);
    }

     

     

    三:线程生命周期:

    新建状态->就绪状态->运行状态->阻塞状态->死亡状态

     

     

    四:线程的一些操作:

    1. 获取并且修改线程的名字

      //用第一种创造线程的方式:
      MyThread t= new MyThread();
      MyThread.setname("新线程");
      String tname=MyThread.getname();
    2. 获取当前线程对象:(有点类似于this指针)

      //获取:static Thread currentThread();
      //调用:Thread Thread.currrentThread();
      Thread t=Thread.currentThread();
      System.out.println(t.getname+"--->"+123123);
      //如果这段代码出现在主线程中,当前线程就是主线程,
      //当t1线程执行该代码,就是t1线程
      //当t2线程执行该代码,就是t2线程
    3. 线程Sleep方法:

      /*
          static void sleep(long millis);
          1.静态方法:Thread.sleep(1000);
          2.参数:毫秒
          3.作用:让当前线程进入休眠《进入“阻塞状态”,放弃占用CPU时间片
          4.Thread.sleep();可以像计时器那样,间隔记录时间
      */
      Thread t=new MyThread();
      t.start();
      try{
          t.sleep(millis:1000*5);
      }catch(InterruptedException e){
          e.printStaclTrace();
      }
    4. 中断睡眠方式:interrupt,但是这种终断睡眠的方式是依靠java的异常处理机制实现的

      public static void main(String[] args) {
          Thread t=new Thread(new MyRunnable2());
          t.setName("t");
          t.start();
          //必须要有try,catch异常机制
          try {
              Thread.sleep(1000*5);
          } catch (InterruptedException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }
          t.interrupt();//这里中断支线程的sleep睡眠
      }
      //这个放在外面就好了,不要放在包创建的class里面
      class MyRunnable2 implements Runnable{
      ​
          @Override
          public void run() {
              // TODO Auto-generated method stub
              try {
                  Thread.sleep(1000*60*60*30);
              } catch (InterruptedException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              }
          }
          
      }
    5. 结束线程:

      //直接杀死线程,直接干掉这个线程(已过时,容易丢是数据)
      跟上面的终止一样,就是最后哪里变成
      t.stop();
      //常用的结束线程,一般就是打一个bollean b标记,如果有问题,将这个变为false,想什么时候结束线程,将该类中b的值改为false,最后来一个return ;
    6. 线程调度:

      1. 实例方法:

        void setPriority(int newPriority);
        int getPriority()//获取线程有优先级
        //最低优先级:1,最高优先级:10,默认优先级:5
            
        //设置优先级:
        Thread.currentThread().setPriority(1);
      2. 静态方法:

        static void yield()//让位方法
        //暂停当前正在执行的线程对象,yield()方法不是阻塞方法,让当前线程让位,让给其他线程使用
        //yield()方法的执行会让当前线程从“运行状态”回到“就绪状态”
        //注意:回到“就绪状态”还有可能再次强到。
            
        //设置让位:
            class MyRunnable6 implements Runnable{
                @Override
                public void run(){
                    for(int i=1;i<10000;i++){
                        //每100个让位一次
                        if(i%100==0){
                            Thread.yield();//当前线程让位
                        }
                        System.out.println(Thread.currentThread().getName()+"---->"+i);
                    }
                }
            }
      3. 线程合并join:同样的,join方法也是需要java异常机制的执行才可以

        void join()
        //合并线程
        class MyThread1 extends Thread{
            public void doSome(){
                Mythread2 t=new MyThread2();
                t.join();//当前线程受阻,t线程执行
            }
        }
    7. 多线程并发环境下,数据安全问题

      1. 重点:以后写代码需要在多线程并发的环境下考虑数据安全的问题

      2. 线程不安全的条件:满足下面三个条件就会有线程安全问题

        1. 多线程并发

        2. 有共享数据

        3. 共享数据有修改的行为

      3. 如何解决线程安全问题:使用线程同步机制,但是会损失一些效率,莫得办法

      4. 哪些数据有数据安全问题:实例变量和静态变量,局部变量没有安全问题

      5. 举例:编写两个线程对同一个账号读取并录入信息使用同步代码快synchronized

    8. 线程同步机制:synchronized

      1. 语法:一般也可以直接在构造方法的时候加入,这样就对类中其中的一种方法加上一个锁

        synchronized(obj/this){
            //线程同步代码快
                    //取款之前的余额
                double before=this.getBalancce();
                //取款之后的余额
                double after=before-money;
                //读取剩下的余额的信息
                this.getBalancce();
        }

        synchronized后面的括号中传的这数据时相当关键的,
        这个数据必须时多线程共享的数据,才能达到多线程排队
        写什么?
           那要看什么线程的同步,或者说填写共享对象
           填写this或者你想同步的那几个线程的共享对象
      2. 原理:java语言当中,每个对象都有一把锁,也就相当于是一个标记,而使用synchronized传递对象的时候,只能同时占有一把锁,所以其他线程只能等候占用锁来继续执行下面的代码。

      3. 三种写法

        第一种:同步代码块:
           灵活
           synchronized(线程共享对象){
           t同步代码快
        }

        第二种:在实例方法中使用synchronized
           表示共享对象一定时this
           并且同步代码快时整个方法体
           
        第三种:在静态方法上使用synchronized,保证静态变量的安全
           表示找类锁
           类锁永远只有一把
           就算创建了100个对象,类锁也只有1个
        public class Exam01{
            public static void  main(String[] args){
                Myclass mc=new Myclass();
                Thread t1=new MyThread(mc);
                Thread t2=new MyThread(mc);
                t1.setName("t1");
                t2.setName("t2");
                
                t1.start();
                Thread.sleep(1000);
                t2.start();
            }
        }
        ​
        class MyThread extends Thread{
            private Myclass=mc;
            public void run(){
                if(Thread.currentThread().getName().equals("t1")){
                    mc.dosome();
                }
                if(Thread.currentThread().getName().equals("t2")){
                    mc.doother();
                }
            }
        }
        ​
        class Myclass{
            public synchronized void dosome(){//这是对象锁,如果前面加一个static,那就是类锁,不管创建了几个对象,都需要等待上一个线程执行完成,才能执行下一个步骤
                System.out.println("dosome begin");
                try{
                    Thread.sleep(1000*10);
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println("dosome over");
                public void doother(){
                    System.println("doother begin");
                    System.println("doother over");
                }
            }
        }
        ​
        ​
        //注意:该线程使用类锁时,dosome有synchronized,但是doother没有synchronized,所以没有排序,两个异步处理,并没有同步,所以不安全
        只有当两个全都有synchronized的时候才会有类锁性质顺序
         
    9. 死锁:直接上手,需要会写死锁

      //一般是使用synchronized的时候,使用了嵌套的方法,可能会死锁,若是在死锁途中还进行睡眠操作,那将会导致程序停留崩溃

      class MyThread1 extends Thread{
          Obiect o1;
          Object o2;    
          
          public void run(){
              synchronized(o1){
                  synchronized(o2){
                      
                  }
              }
          }
      } 
      ​
      class MyThread2 extends Thread{
          Obiect o1;
          Object o2;    
          
          public void run(){//这里的两个object位置互换了一下
              synchronized(o2){
                  synchronized(o1){
                      
                  }
              }
          }
      } 
      ​
      //以上代码,在main类中同步调用的时候,也就是MyThread1.start();MyThread2.start();会出现死锁现象,导致程序暂停。
       
    10. 如何解决线程安全问题?(这个之后再说吧)

      1. 创建局部变量,没有安全问题
      2. 创建多个实例对象,实例变量的内存就不共享了
      3. 啥都不能用的话,只能适合用synchronized了

     

  • 相关阅读:
    Error: unable to load xmlsec-openssl library
    count(1)、count(*)与count(列名)的执行区别
    Linux下的压缩zip,解压缩unzip命令详解及实例
    linux centos 如何查看操作系统版本信息
    These dependencies were not found: *!!vue-style-loader!css-loader?
    Git如何永久删除某个重要文件文件或文件夹 (包括历史记录) 强制
    LDAP的filter查询详解
    详谈mysqldump数据导出的问题
    GO -- 遍历删除 数组 slice
    mjml强大&&灵活的邮件模版引擎
  • 原文地址:https://www.cnblogs.com/instead-everyone/p/13619071.html
Copyright © 2011-2022 走看看