Thread

多线程

1、创建多线程
    * 方式1:创建Thread子类
        *步骤
            1、创建一个Thread类的子类
            2、在Thread类的子类中重写Thread类中的run()方法
            3、创建Thread的子类对象
            4、调用Thread类的start()开启线程

    *方式2:实现Runnable接口
        *步骤
            1、创建一个Runnable接口的实现类
            2、在实现类中重写Runnable接口的run()方法
            3、创建一个Runnable实现类对象
            4、创建Thread类对象,构造方法传入Runnable实现类对象
            5、调用Thread类中的start()方法开启线程

    *两种方式的区别:

        1、实现Runnable接口避免了单继承的局限性
        2、增强了程序扩展性,降低了程序的耦合性(Runnable实现任务,Thread开启线程)

线程安全

    1、同步代码块

        *格式:
            synchronized(锁对象){
                可能出现线程安全的代码
            }
        *注意:
            1、通过代码块中的锁对象,可以使用任意的对象
            2、但必须保证多个线程使用的锁对象是同一个
            3、锁对象的作用把同步代码块锁住,只让一个线程在同步代码块中执行
        *步骤:

            创建锁对象:Object obj = new Object();
                synchronized(obj){
                    可能出现线程安全的代码
                }

        *原理:
            使用了一个锁对象,这个锁对象叫同步锁,同步中的线程没有执行完毕不会释放锁,
            同步外的线程没有锁不能进入同步块中
    
    2、同步方法

        *步骤
            1、把访问共享数据的代码抽取出来,放到一个方法中
            2、在方法上添加synchronized修饰符
            修饰符 synchronized 返回值类型 方法名(参数列表){
                    可能出现线程安全的代码
            }

    3、静态同步方法
        
        修饰符 static synchronized 返回值类型 方法名(参数列表){
                可能出现线程安全的代码
        }
        锁对象是class

    4、Lock

        * 步骤
            1、在成员位置创建一个ReentrantLock对象
            2、在可能出现安全问题的代码前调用Lock接口的lock()获取锁
            3、在可能出现安全问题的代码后调用Lock接口的unlock()释放锁
            Lock l = new ReentrantLock();
            l.lock();
            可能出现线程安全的代码
            l.unlock();

等待唤醒机制

1、为什么处理线程间通信?
    多线程并发执行时,在默认情况下CPU随机切换线程,当我们需要多个线程共同完成一个任务,
    并且我们希望它们由规律的执行,那么多线程需要一些协调通信,以此来帮助我们达到多线程
    共同操作同一份数据

2、wait()和notify()注意的细节?
    *wait()和notify()必须由同一锁调用
    *wait()和notify()都属于Object中的方法
    *wait()和notify()必须在同步代码块或同步函数中使用
3、案例

    资源类:
        public class Resource {
            private String name;
            private int num = 1;
            private boolean flag = false;
            Lock lock = new ReentrantLock();//创建锁对象
            Condition producter = lock.newCondition();//获取监视生产者的锁
            Condition consumer = lock.newCondition();//获取监视消费者的锁
            public void setKind(String name){
                lock.lock();//获取锁
                try{
                    while(flag) { // 有烤鸭,生产者等待
                        try {
                            producter.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                        this.name = name + num;
                        num++;
                        System.out.println("生产者"+ this.name);
                        flag = true;
                        consumer.signal();
        
        
                }finally{
                    lock.unlock();//释放锁
                }
            }
        
            public void out(){
                lock.lock();
                try{
                    while(!flag) {//没有烤鸭,消费者处于等待状态
                        try {
                            consumer.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                        System.out.println("消费者"+ this.name);
                        flag = false;
                        producter.signal();
        
        
                }finally{
                    lock.unlock();
                }
        
            }
        
        }

    生产者类

        public class Producter implements Runnable{
            Resource r;
            public Producter(Resource r){
                this.r = r;
            }
            @Override
            public void run() {
                while(true){
                    r.setKind("烤鸭");
                }
            }
        }

    消费者类

        public class Consumer implements Runnable{
            Resource r;
            public Consumer(Resource r){
                this.r = r;
            }
            @Override
            public void run() {
                while (true){
                    r.out();
                }
            }
        }

    测试类

        public class Demo {
            public static void main(String[] args) {
                Resource r = new Resource();
                Producter a = new Producter(r);
                Consumer b = new Consumer(r);
                Thread t1 = new Thread(a);
                Thread t2 = new Thread(a);
                Thread t3 = new Thread(b);
                Thread t4 = new Thread(b);
                t1.start();
                t2.start();
                t3.start();
                t4.start();
            }
        }

线程池

1、原理

    *当程序第一次启动时,创建多个线程保存到一个集合中当我们想要使用线程时,就可以从集合把
    线程取出来
        Thread t = arrayList.remove() //从集合中取出
        Thread t = linkedList.removeFirst()
    *当使用完毕把线程归还到线程池,JDK1.5之后,JDK内置了线程池
        arrayList.add(t)
        linkedList.addLast(t)

2、优点
    * 降低资源消耗,降低了创建和销毁线程的次数
    * 提高响应速度,不需要等待创建线程
    * 提高线程的可管理性

3、用到的类
    * java.util.concurrent.Executors; //线程池的工厂类,用来生产线程池
    * Executors类中的静态方法
        static ExecutorService newFixedThreadPool(int nThread)
        创建一个可重用固定线程数的线程池
        返回值:ExecutorService接口类型,返回ExecutorService实现类对象
        ExecutorService为线程池接口,用来从线程池获取线程
            调用start()执行线程任务
            submit(Runnable task)提交一个Runnable任务用于执行
4、步骤
    1、使用线程池工厂类Executors里提供的静态方法newFixedThreadPool生产一个线程池
    2、创建一个类实现Runnable接口,重写run()方法设置线程任务
    3、调用ExecutorService中的submit(),传递线程任务(实现类),开启线程
    4、调用ExecutorService中的shutdown销毁线程池(不建议执行)

    ExecutorService es = Executors.newFixedThreadPool(10);
    //线程池会一值开启,使用完了线程,会自动把线程归还给线程池
    es.submit(new RunnableImpl());
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容