首页 > 代码库 > j2ee(5) 线程

j2ee(5) 线程

1.理清概念 并行与并发:    *并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。    *并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。            2.线程创建    * 继承thread类创建多线程            public class Example01 {            public static void main(String[] args) {                                MyThread myThread = new MyThread();        //创建线程 MyThread 的线程对象                myThread.start();                        //开启线程                                while(true){                    System.out.println("main 方法在运行");                }                                            }        }        class MyThread extends Thread{                        public void run(){                while (true){                    System.out.println("MyThread 类的 run()方法在运行");                }            }        }            * 实现Runnable接口创建线程            public class Example01 {            public static void main(String[] args) {                                MyThread myThread = new MyThread();        //创建线程 MyThread 的线程对象                Thread thread = new Thread(myThread);   //创建线程对象                thread.start();                          //开启线程,执行线程中的run()方法                                while(true){                    System.out.println("main 方法在运行");                }                            }        }        class MyThread implements Runnable{                        public void run(){                while (true){                    System.out.println("MyThread 类的 run()方法在运行");                }            }        }                    * 两种实现多线程方式的对比分析,实现Runnable接口相对于继承Thread类有如下显著的好处        1.可以避免由于java的单继承带来的局限。java不支持多继承(子类不能有多个父类),其他类的子类不能用继承Thread类的方式,只能采用实现Runnable接口的方式        2.适合多个相同程序代码的线程去处理同一个资源的情况,把线程同程序代码、数据有效的分离            * 后台进程      --如果某个线程对象在启动之前调用了setDaemon(true)语句,这个线程就变成一个后台进程      --当前台线程结束后,JVM会通知后台线程      --进程中只有后台线程运行时,进程会结束            3.线程的调度    * 线程的优先级      --static int MAX_PRIORITY        表示线程的最高优先级 相当于值10      --static int MIN_PRIORITY        表示线程的最低优先级 相当于值1      --static int NORM_PRIORITY    表示线程的普通优先级 相当于值5        * 线程休眠      --Thread.sleep()            * 线程让步      --Thread.yield()            * 线程插队      --join()    4.多线程同步    * 线程安全      --多个线程同时去访问同一个资源时,易引发安全问题。            *同步代码块        class Ticket1 implements Runnable{                        private int tickets = 10;            //定义变量 赋值                Object lock = new Object();            //定义任意一个对象,用作同步代码块的锁                        public void run(){                                while (true){                    synchronized(lock){            //定义同步代码块                                                try {                            Thread.sleep(2000);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                                                if(tickets >0){                            System.out.println(Thread.currentThread().getName()+"---卖出的票---"+tickets--);                        }else{                            break;                        }                    }                }                            }        }        public class Example01 {            public static void main(String[] args) {                Ticket1 ticket = new Ticket1();                //创建 Ticket1 对象                 //创建并开启四个线程                new Thread(ticket,"线程1").start();                        new Thread(ticket,"线程2").start();                new Thread(ticket,"线程3").start();                new Thread(ticket,"线程4").start();            }        }                *同步方法            class Ticket1 implements Runnable{                        private int tickets = 10;            //定义变量 赋值                public void run(){                while (true){                        saleTicket();                        if(tickets <=0){                            break;                        }                }            }                        //定义一个同步方法saleTicket()            private synchronized void saleTicket(){                if(tickets > 0){                    try {                        Thread.sleep(2000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                                System.out.println(Thread.currentThread().getName()+"---卖出的票---"+tickets--);                }            }            }        public class Example01 {            public static void main(String[] args) {                Ticket1 ticket = new Ticket1();                //创建 Ticket1 对象                 //创建并开启四个线程                new Thread(ticket,"线程1").start();                        new Thread(ticket,"线程2").start();                new Thread(ticket,"线程3").start();                new Thread(ticket,"线程4").start();            }        }            *锁死问题        5.多线程通信    *问题引入:假设有两个线程同时去操作同一个存储空间,其中一个线程负责向存储空间中存入数据,另一个线程负责取出数据。        --数据存储类        public class Storage {            //数据存储数组            private int[] cells = new int[10];                        //inPos 表示存入时数组下标,outPos表示取出时数组下标            private int inPos,outPos;                        //定义一个put()方法向数组中存入数据                        public void put(int num){                cells[inPos] = num;                System.out.println("在cells["+inPos+"]中放入数据--"+cells[inPos]);                inPos++;                if(inPos == cells.length)                    inPos = 0;                //当inPos为数组长度时 将其置为0            }                        //定义一个get()方法从数组中取出数据            public void get(){                int data = http://www.mamicode.com/cells[outPos];"在cells["+outPos+"]中取出数据--"+data);                outPos++;                if(outPos == cells.length)                    outPos = 0;                //当outPos为数组长度时 将其置为0            }                }    --数据存取类        public class Input implements Runnable {                        private Storage st;                        private int num;                        Input (Storage st){                //通过构造方法接收一个Storage对象                this.st= st;            }            @Override            public void run() {                while(true){                    st.put(num++);            //将num存入数组,每次存入后num自增                }            }        }        public class Output implements Runnable {                        private Storage st;            Output(Storage st){                    //通过构造方法接收一个Storage对象                this.st = st;            }                        @Override            public void run() {                while(true){                    st.get();                }            }        }            --创建线程            public class ExampleTest02 {            public static void main(String[] args) {                                Storage st = new Storage();                //创建数据存储对象                Input input = new Input(st);            //创建Input对象传入Storage对象                Output output=new Output(st);            //创建Output对象传入Storage对象                                new Thread(input).start();                //开启新线程                new Thread(output).start();                //开启新线程            }        }                * 问题解决:测试发现上述存取进程是随机的,未按照顺序轮流执行。如需按照一定顺序轮流执行,此时需要让进程间进行通信    --在Object类中提供了wait(),notify(),notifyAll()方法用于解决线程间的通信问题,因为Java中的所有类都是Object类的子类或间接子类,因此任何类的实例对象都可以直接使用这些方法。    --void wait()  使当前线程放弃同步锁并进入等待,直到其他线程进入此同步锁,并调用notify()或notifyAll()方法唤醒该线程为止    --void notify() 唤醒此同步锁上等待的第一个调用wait()方法的线程    --void notifyAll() 唤醒此同步锁上调用wait()方法的所有线程        public class Storage {                private int[] cells = new int[10];    //数据存储数组                private int inPos,outPos;            //inPos 表示存入时数组下标,outPos表示取出时数组下标            private int count;                    //存入或取出数据的数量                        //定义一个put()方法向数组中存入数据            public synchronized void put(int num){                                //存入数据如果等于cells的长度,此线程等待                while(count == cells.length){                    try {                        this.wait();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }                cells[inPos] = num;                System.out.println("在cells["+inPos+"]中放入数据--"+cells[inPos]);                inPos++;                if(inPos == cells.length)                    inPos = 0;                //当inPos为数组长度时 将其置为0                                count++;                this.notify();            }                        //定义一个get()方法从数组中取出数据            public synchronized void get(){                                while(count == 0){         //如果count为0 此线程等待                    try {                        this.wait();                    } catch (InterruptedException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    }                }                int data = http://www.mamicode.com/cells[outPos];"在cells["+outPos+"]中取出数据:"+data);                cells[outPos] = 0;                outPos++;                if(outPos == cells.length)                    outPos = 0;                //当outPos为数组长度时 将其置为0                count--;                this.notify();            }                }            注意:如果wait(),notify(),notifyAll()方法调用者不是同步锁对象,JVM会抛出 java.lang.IllegalMonitorStateException            

 

j2ee(5) 线程