zoukankan      html  css  js  c++  java
  • 线程知识总结

    进程就是一个正在运行的程序,分配内存让应用程序能够运行。

     

           Windows系统号称多任务(可以同时运行多个应用程序)。

               宏观上看:Windows确实是运行多个程序。

               微观上看:CPU快速切换执行任务,由于速度特别快,我们人感觉不到这个切换的过程

     

    线程在一个进程中负责代码的执行,就是进程中的执行路径。

      

     疑问:没有主线程,为什么代码可以执行?

            java程序在运行的时候,jvm会帮我们创建一个主线程来执行代码。主线程主要负责main方法中的代码执行。

       

     一个java程序中至少有2个线程

           一个主线程主要负责main方法中的代码执行,一个垃圾回收器线程,负责垃圾回收。

       多线程:在一个进程中多个线程同时执行不同的任务。

       “同时”:单核CPU快速切换多个线程执行任务

                速度特别快,人感觉不到切换。

     

    多线程的好处:

           1.解决一个进程中同时执行多个任务的问题、

           2.提高资源的利用率。

      

    多线程的弊端:

           1.增加CPU的负担。线程不是越多越好。

           2.降低了一个进程中线程的执行效率。

           3.容易引发线程安全问题。

           4.出现死锁现象。

     java中创建线程有2种方式

          线程的定义方式一Thread (线程类)

            1.需要定义一个类来继承Thread类。

            2.重写thread类中run方法,把自定义线程的任务代码写在run方法中。

                   * 每一个线程都有自己的任务代码,jvm创建的主线程任务代码就是main方法,

                   * 自定义的线程的任务代码就写在run方法中,自定义的线程就需要执行run方法中的代码。

            3.创建Thread的子类,并且调用start方法开启线程。

               

         注意点:一旦线程开启了,会默认执行线程对象中的run方法,但是千万不要自己直接调用run方法,如果直接调用了run方法,就和普通方法没有区别。

        Java 是单线程,如果一个类已经继承了别的类,这个时候就不能够通过继承thread类来创建线程了。

      

    线程的使用细节:

           1.线程的启动使用父类的start()方法

           2.如果线程对象直接调用run(),那么JVm不会当作线程来运行,会认为是普通的方法调用。

           3.线程的启动只能由一次,否则抛出异常

           4.可以直接创建Thread类的对象并启动该线程,但是如果没有重写run(),什么也不执行。

           5.匿名内部类的线程实现方式

       线程的定义方式二:

         1.自定义一个类实现Runable接口  , 接口中就会提供一个run方法

         2.实现Runable接口中的run方法。将线程中的任务写在run方法中

         3.创建Runable接口的实现类对象

           注意点:实现runnable接口的类不是一个实现类,他是没有能力开启线程的只有是thread或者他的子类才是线程类,只有他们才有开启线程的能力。

         4.创建一个Thread对象,并把Runable实现类创建的对象作为参数。

         5.调用Thread对象的start方法来开启线程

      

     问题 为什么要将Runable接口实现类的对象作为参数传递?

          为了让对象中的run方法能够在线程中的run方法中执行。也就是能够将对象中的run方法最为线程中的任务来执行

         

     *  推荐使用 :第二种方式  实现Runable.

     *  java 是单继承 ,多实现的

        售票的线程方式一(thread):

    class SaleTickets extends Thread {
        static int num = 50; // 总票数 共享的数据,三个窗口同时操作同一份数据
        //static Object o = new Object();
        public SaleTickets (String name) {
            super(name);
        }
       // 重写run方法:卖票的任务
        public void run() {
           
            while (true) {
                synchronized ("hh") { //任意类型的对象,锁对象应该是同一个对象
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        // TODO: handle exception
                        e.printStackTrace();
                    }
                    if(num > 0) {
                        System.out.println(this.getName() + "卖了第" + num + "票");
                        num--;
                    
                    } else {
                        System.out.println("票已售完");
                        break;
                    }
                }
            
                
            }
        }
        
    }
    public class Demo4 {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            // TODO Auto-generated method stub
           SaleTickets t1 = new SaleTickets("窗口1");
           SaleTickets t2 = new SaleTickets("窗口2");
           SaleTickets t3 = new SaleTickets("窗口3");
           t1.start();
           t2.start();
           t3.start();
        }
    
    }

    售票的线程方式二(Runnable):

    class SaleTickets1 implements Runnable {
        static int num = 50;
         public void run() {
             while (true) {
                 synchronized ("djj") {
                     if (num > 0) {
                            System.out.println(Thread.currentThread().getName() + "卖出第" + num + "张票");
                            num--;
                        } else {
                            System.out.println("票已售尽");
                             break;
                        }
                 }
                
            }
            
        }
    }
    public class Demo8 {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            //创建实现类对象
           SaleTickets1 st = new SaleTickets1();
           // 创建三个线程对象
           Thread t = new Thread(st, "窗口1");
           Thread t1 = new Thread(st, "窗口2");
           Thread t2 = new Thread(st, "窗口3");
           t.start();
           t1.start();
           t2.start();
        }
    
    }
    
    

    java给线程加锁 :

    解决线程安全问题的手段:

    通过同步代码的方式:

        方式一:同步代码块

           锁对象可以是任意一个java中的对象

            java中的任意一个对象都会有一个对象的状态 ,就可以通过对象的状态来作为锁的一个标识符。

         state = 0 表示锁是关闭   state = 1 表示锁打开。

           synchronized (锁对象) {

       }

    同步代码块的使用注意点

             1.任意一个对象都可以做锁对象

            2.如果你在同步代码块中调用了sleep方法 ,不会释放锁对象

           3.只有真正存在线程安全的时候才需要使用同步代码块,否则会降低执行效率

           4.多线程操作锁对象必须是唯一的 ,否则无效

    方式二:同步函数

           写法:用synchronize来修饰方法。

           如果同步函数是一个非静态的函数:锁对象就是调用者对象。

           如果同步函数是一个静态的函数:锁对象同步函数是所在类的字节码(Class对象)

    同步函数和同步代码块的区别:

           1.同步代码块,可以随意确定同步代码的范围,同步函数只能同步整个函数的代码。

           2.同步代码块的锁对象可以自己任意指定,同步函数的锁对象是固定的。

    不知道什么时候安全什么时候不安全。

    出现线程安全的问题根本原因:

         1.存在两个或两个以上的线程。并且线程之间共享着一个资源。

         2.多个语句操作了共享资源

    线程死锁:

     但是如果使用不当会导致线程死锁问题:

      A线程等B线程完成, B线程又在等A线程   结果两个人就一直等下去了 ,这个时候就造成了线程死锁。

      线程死锁不一定会出现,有可能会出现。

      死锁现象的解决方案 :  没有方案 ,尽量避免发生。

    实例:

    class DeadLock extends Thread {
        public DeadLock(String name){
            
            super(name);
        }
        
        @Override
        public void run() {
            
            
            if("张三".equals(Thread.currentThread().getName())){
                
                synchronized ("遥控器") { //锁对象就锁住了
                    
                    System.out.println("张三拿到了遥控器 ,准备去拿电池");
                    
                    synchronized ("电池") {//已经被锁住了
                        
                        System.out.println("张三拿到了遥控器和电池,开着空调,在也 不冷了");
                    }
                }
            }else if("老王".equals(Thread.currentThread().getName())){
                
                synchronized ("电池") { //锁也被锁住了  电池对象的状态 变为锁住的状态
                    
                    System.out.println("老王拿到电池,准备去拿遥控器");
                    
                    synchronized ("遥控器") { //遥控器也被锁住了
                        
                        System.out.println("老王拿到了遥控器和电池,开着空调,在也 不冷了");
                    }
                }
            }
            
        }
        
    }
    
    public class Demo6 {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            
            DeadLock t1 = new DeadLock("张三");
            t1.start();
            DeadLock t2 = new DeadLock("老王");
            t2.start();
        

    线程的通讯:

      线程的通讯:一个线程完成自己的任务,去通知另外一个线程去完成另外一个任务。

        wait();  等待      如果线程执行了wait方法 ,那么该线程就会处于一个等待状态,等待状态的线程必须要通过其他线程来调用

        notify()方法来唤醒。

        notify();唤醒   随机唤醒线程池中的一个线程。

         notifyAll(); 唤醒所有等待的线程。

     waitnotify的使用注意点 :

       1.wait方法和notify方法是属性Object对象

       2.wait方法和notify方法必须在同步线程中执行

       3.wait方法和notify方法必须有锁对象来调用

    消费者和生产者之间的通讯:

    class Product {
        
        String name;
        double price;
        
    }
    
    class Producter extends Thread{  //生产产品
        Product p;
        
        public Producter(Product p){
            
            this.p = p;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            
            for(int i = 0;i<50;i++){
                
                synchronized (p) {
                    
                    if(i % 2 == 0){
                        p.name = "苹果";
                        p.price = 3.5;
                        System.out.println(p.name+":"+p.price);
                    }else {
                        
                        p.name = "香蕉";
                        p.price = 2.0;
                        System.out.println(p.name+":"+p.price);
                    }
                    
                    //产品以经生产出来 唤醒消费者来消费
                    p.notify();
                    
                    try {
                        p.wait(); // 等待消费者提醒
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    
                    
                }
            }
            
        }
    }
    
    class Custem extends Thread{
        
        Product p; // 消费者消费的产品
        
        public Custem(Product p){
            
            this.p = p;
        }
        
        @Override
        public void run() {
            // TODO Auto-generated method stub
            
            for (int i = 0;i<50;i++){
                synchronized (p) {
                    //通过锁对象来调用
                    if(p.name != null){
                        System.out.println("吃"+p.name+":"+p.price);
                    } // 没有产品  告诉生产者需要生产产品
                        
                    //唤醒生产者
                    p.notify();
                    try {
                        p.wait();  //等待产品创建
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    public class Demo9 {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            //创建一个产品对象
            Product p = new Product();
            
            //创建一个生产者
            Producter t1 = new Producter(p);
            
            //创建一个消费者
            Custem t2 = new Custem(p);
            
            t1.start();
            t2.start();
            
    
        }
    
    }
  • 相关阅读:
    Unix环境高级编程—进程关系
    如何学习CCIE
    Unix环境高级编程—进程控制(三)
    Unix环境高级编程—进程控制(二)
    _THROW 何解?
    Unix高级环境编程—进程控制(一)
    ifndef/define/endif 和 #ifdef 、#if 作用和用法
    内存MCE错误导致暴力扩充messages日志 以及chattr记录
    Intellij IDEA的安装和激活
    Xshell和Xftp间隔一段时间不操作就自动断开连接?
  • 原文地址:https://www.cnblogs.com/binzhihua-666/p/6128114.html
Copyright © 2011-2022 走看看