• 多线程


    1. 进程:一个程序是一个进程,一个程序主函数执行就是一个进程,电脑上可以同时有多个进程同时运行,叫并发。2个CPU4个核一共就能并行4个程序,进程多,按时间片轮转获得资源。

    2. 线程:一个进程可以包含多个线程,如启动一个QQ是一个进程,QQ同时可以聊天,可以弹广告消息,线程是进程的一个执行线索,线程数多的时候,线程数跟核数相等就并行,不等就时间片轮转。

    3. 进程之间交互通信,不方便,线程之间很很方便(一个进程内的)。

    4. 程序运行时,先启动线程,按照代码(线路)来执行。

    5. 继承Thread类实现多线程:1. 自己实现的线程类要继承Thread类 2. 重写run()方法,run方法里是该线程要执行的操作。

                                           开启线程方法:new线程类对象,用该对象调用start()方法。start方法会调用ran方法。

                  如果直接调用run方法,如果run方法是死循环,就会一直执行run方法,这样就是自己实现的线程的线程一直在跑,

                  无法执行其他线程,就是资源都被这个线程占用,这个线程一直在执行,直到执行结束。

                  调用start方法会在线程启动前向系统申请资源,分配执行的时间片,申请到cpu后,再调用run()方法执行。

    6 .实现Runnable接口: 1.自己实现的线程类要实现Runnable类,Runnable接口中只定义了一个run()方法,2.自己实现的类中实现run()方法。

                                    开启线程方法:new Thread(new RunTread()).start(); 其实是Thread类中有个构造方法 Thread(Runnable runnable)可以传

                实现了Runnable接口的子类,启动线程还是调用了Thread类的start()方法。

                这种方式就是不用继承Thread类,自己实现的线程类可以继承别的类了。

    7. start()方法如何申请资源: 源码中可以看成 start方法调用源码中一个native的start0方法来实现资源配置。native方法为java与非java代码交互的关键字,

                   如调用c代码,JVM将控制调用本地方法的所有细节,具体看另外native博客。

       源码:

     public synchronized void start() {
            /**
             * This method is not invoked for the main method thread or "system"
             * group threads created/set up by the VM. Any new functionality added
             * to this method in the future may have to also be added to the VM.
             *
             * A zero status value corresponds to state "NEW".
             */
            if (threadStatus != 0)
                throw new IllegalThreadStateException();
    
            /* Notify the group that this thread is about to be started
             * so that it can be added to the group's list of threads
             * and the group's unstarted count can be decremented. */
            group.add(this);
    
            boolean started = false;
            try {
                start0();
                started = true;
            } finally {
                try {
                    if (!started) {
                        group.threadStartFailed(this);
                    }
                } catch (Throwable ignore) {
                    /* do nothing. If start0 threw a Throwable then
                      it will be passed up the call stack */
                }
            }
        }
    
        private native void start0();
    
        /**
         * If this thread was constructed using a separate
         * <code>Runnable</code> run object, then that
         * <code>Runnable</code> object's <code>run</code> method is called;
         * otherwise, this method does nothing and returns.
         * <p>
         * Subclasses of <code>Thread</code> should override this method.
         *
         * @see     #start()
         * @see     #stop()
         * @see     #Thread(ThreadGroup, Runnable, String)
         */
        @Override
        public void run() {
            if (target != null) {
                target.run();
            }
        }

    8. 进程分为前台进程和后台进程 后台进程在主函数(也是个进程)中执行的话,如果主函数进程结束,后台进程也结束,前台进程则不受影响。后台线程也叫守护线程。

    public static void main(String[] args) {
            Thread t = new Ticket();
            t.setDaemon(true);//设置为后台进程
            t.start();

    9. 线程的联合 join 

    package weiguoyuan.chainunicom.cn;
    
    class Ticket extends Thread {
        public void run() {
            while(true) {
                System.out.println(Thread.currentThread().getName()+ " );
            }        
        }
    }
    
    
    public class TestThread {
    
        public static void main(String[] args) throws InterruptedException {
            Thread t = new Ticket();
            t.start();
            
            int i = 0;        
            while(true) {
                i++;
                System.out.println(Thread.currentThread().getName());
                if(i==10000) {
                    t.join(6666); //6666为毫秒数 ,将t线程联合过来 只执行t直到6666毫秒过后 恢复
                }
            }
        }
    
    }

    10. 例子 经典卖票程序 3窗口卖1000

    <1. 3个线程 分别有自己的tickets 这样就卖出了 3000张票

    package weiguoyuan.chainunicom.cn;
    
    class Ticket extends Thread {
        private int tickets = 1000;
        public void run() {
            while(tickets>0) {
                System.out.println(Thread.currentThread().getName()+ " "+tickets--);
            }        
        }
    }
    
    public class TestThread {
    
        public static void main(String[] args) {
            new Ticket().start();
            new Ticket().start();
            new Ticket().start();
        }
    }

    <2. 在tickets上加上static 资源共享 3个线程动作相同 瓜分现象

    private static int tickets = 1000;

    <3. 线程的同步问题,当多个线程同时进入run()方法中,操作tickets--,如假如当前tickets为1,1,2线程两个线程,1线程先得到时间片判断tickets>0,然后还没执行到tickets--这句代码,2号线程抢到时间片进入run()方法也判断tickets>0,然后执行tickets--,这时tickets已经为0了,结束线程,这时1线程得到时间片执行tickets--,tickets=-1,显然已经出错。

    解决办法:用锁锁住run()方法,锁住判断和操作资源,让这两步为一个原子,当一个线程进来判断时,不允许其他进程进入。

         第一种锁: synchronized 同步代码块,同步的 的意思,实现方法:Object类,即每个对象都有2种状态,低电平0和高电平1,synchronized通过有线程进入该方法就改变,传入的对象的状态来锁定一段代码,如有线程进入则改变对象的状态为1,其他进程过来时synchronized判断自己的对象为1则不让该线程进入,进入的线程执行结束后将对象的状态改为0,其他线程才可以进入。

    package weiguoyuan.chainunicom.cn;
    
    class Ticket extends Thread {
        private int tickets = 1000;
    private Object obj;
    public void run() { while(true){ synchronized(obj) {//利用obj上锁 if (tickets>0) { System.out.println(Thread.currentThread().getName()+ " "+tickets--); } } } } } public class TestThread { public static void main(String[] args) { Ticket t = new Ticket(); t.start(); t.start(); t.start(); } }

             第二种锁:synchronized 同步函数

    package weiguoyuan.chainunicom.cn;
    
    class Ticket extends Thread {
        private int tickets = 1000;
        public void run() {
            while(true){
               saleTickets();//原子性代码抽取成同步函数
            }        
        }
        public synchronized void saleTickets() {//这个谁调用synchronized  锁的就是谁 其实这3个线程都用的t这个对象调用该方法来同步
                         if (tickets>0) {                                       
                   System.out.println(Thread.currentThread().getName()+ " "+tickets--); } } } public class TestThread { public static void main(String[] args) { Ticket t = new Ticket(); t.start(); t.start(); t.start(); } }

    还可以用lock接口 主要用到的子类为ReentrantLock 来做同步(主要)有lock()和 unlock()方法 (finally 一定要执行的) 

    11 死锁问题:比如两个线程 都是要得到磁盘和cpu才能运行,一个得到了磁盘,一个得到了cpu,都不释放资源,谁都运行不了

    12 线程之间的通信,Thread类中有 sleep()方法释放cpu和资源,Object类里有 wait(),notify()方法使当前线程等待和唤醒在此对象监视器上等待的单个线程,Object就是看成资源类(磁盘.notify()队列中一个等待的线程,这个线程就可以得到磁盘了)。

  • 相关阅读:
    嵌入式
    IT 管理
    linux 网络编程 排序
    linux frameBuffer
    虚拟现实
    vc 串口
    OpenGLES 图像
    runloop
    归档
    商标查询
  • 原文地址:https://www.cnblogs.com/weixiaole/p/4572154.html
Copyright © 2020-2023  润新知