• 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
        
        
        
  • 相关阅读:
    Django 框架篇(四) : 视图(view)详解 及 路由系统(url)
    Django 框架篇(三) : Django之模板
    Django 框架篇(二) : 创建APP之视图函数; model(模型)系统操作数据库之ORM操作;
    Django 框架篇: 一. Django介绍; 二. 安装; 三. 创建项目;
    212
    redux:applyMiddleware源码解读
    react 反模式——不使用jsx动态显示异步组件
    angular 动态组件类型
    webpack2-webpack.config.js配置
    tdd:(react + mocha)环境配置
  • 原文地址:https://www.cnblogs.com/polestar/p/7131374.html
Copyright © 2020-2023  润新知