java(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 = cells[outPos];
                System.out.println("在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 = cells[outPos];
                System.out.println("在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
    
    
    

 

posted @ 2017-07-07 11:40  PoleStar  阅读(240)  评论(0编辑  收藏  举报