Java必知必会--多线程解析基础篇

2019-03-02 05:36:42  卢浮宫  阅读量:153  版权声明:本文为站长原创文章,转载请写明出处


一、多线程是实现(这里介绍常用的两个)

        1、实现Runnable接口,重写run方法,代码如下:

            public class XaThread implements Runnable {


                public static void main(String[] args) throws InterruptedException {
                    XaThread xaThread = new XaThread();
                    Thread mThread = new Thread(xaThread);
                    mThread.start();
                }

                @Override
                public void run() {
                    for (int i = 0; i < 100; i++) {
                        System.out.println(i);
                        try {
                            Thread.sleep(2000);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

        2、继承Thread类,代码如下:

            public class Xthread{

                public static void main(String[] args) {
                    Thread myThread = new MyThread();
                    myThread.start();
                }
        }

        class MyThread extends Thread{
            public void run(){
                for (int i = 0; i < 100; i++) {
                    System.out.println(i);
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        3、两者对比:

             ①继承Thread类后就是单继承了,会隔绝来自其他类的继承,而实现Runnable接口则消除了这种不良。

              ②class Thread implements Runnable {...}可以看到继承了Thread类后还是要实现Runnable接口,会产生多个Runnable示例对象。而实现Runnable则不会,可以多线程处理同一资源,使用一个Runnable示例产生多个线程,且可以资源共享。


        二、线程的5种状态以及切换

                ①新建:新建了一个线程(继承Thread类或实现Runnable接口)

                ②可运行:线程创建后且调用了start方法,则进入线程池,等待被线程调度选用,获取cpu的使用权

                ③运行:可执行的线程获取到了cpu资源,并执行程序代码

                ④阻塞:线程因为某种原因放弃了cpu使用权,暂停了操作,直到转换成可运行状态才有机会继续进行操作。

                ⑤死亡:线程run()main()方法执行完成,或者异常抛出后,线程结束,且不可恢复。


        三、阻塞状态

                1、当前线程运行Thread.sleep(1000);会使当前线程休眠1s,进入阻塞状态

                2、运行在当前线程(Thread1)的其他线程(Thread2)调用join方法时,会把Thread2加入执行,Thread1阻塞

                3、等待用户输入时(执行IO操作)当前线程进入阻塞状态

                4、使用Thread.sleep(1000);当前线程阻塞,但不释放对象锁

                5、Thread.join();当前线程进入阻塞,但不释放对象锁,等待Thread完成后继续运行

                6、Object.wait();线程进入阻塞,同时释放对象锁,进入等待列队。使用notify()、或notifyAll()可以唤醒

                7、notify()是唤醒一个任意线程,notifyAll()是唤醒所有等待的线程


        四、锁--乐观锁和悲观锁

                1、锁是只有在同步中才有的概念。

                2、乐观锁和悲观锁不单单指锁的类型,事实上是指怎么对待数据并发同步

                3、悲观锁认为数据被拿走就会被修改,所以在每次拿数据时都会上锁。别人在拿这个数据时就会阻塞,知道它获取到锁

                4、乐观锁则认为数据被拿走后不会被修改,所以不会上锁。但是要注意:需要判断期间数据有没有被修改过。

                5、java中的synchronized就是实现的悲观锁,而乐观锁则适用与读操作比较频繁情况(可以提高吞吐量)


                1、死锁的原因及排查方案

                    死锁的本质在于对资源的不良竞争。当多线程同时被阻塞,他们中的一个或全部都在等待一个资源被释放,但是这个资源又被其他线程锁定,

                 2、死锁的产生条件:

                     ①互斥占用:一个资源被占用时其他不能使用。②不可抢占:只能等待资源被释放。③请求和保持:请求其他资源时保持对原有资源占用。④循环:1占用2,2占用3,3占用4,4占用1(花盆上的毛毛虫)


        五、线程同步

               1、不可避免会有使用同步的情况,关于线程同步有以下方案:①在同步方法中假如synchronize关键字 ②使用synchronize快对代码段进行同步处理 

         

        六、经典的生产消费逻辑代码

              public class ProAndCon {
                //定义最大容量
                private int maxNum = 2;
                //产品储存
                private LinkedList<Integer> list = new LinkedList<>();

                class Producer implements Runnable{

                @Override
                public void run() {
                    synchronized(list){
                    while(list.size() == maxNum){
                        System.out.println("仓库已满,停止生产");
                        try {
                            list.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    list.add(1);
                    System.out.println("生产中,数量为--" + list.size());
                    list.notify();
                }
            }
        }

        class Customer implements Runnable{

            @Override
            public void run() {
            synchronized(list){
                while(list.size() == 0){
                    System.out.println("没有库存,停止消费");
                    try {
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                list.removeFirst();
                System.out.println("消费量一个,当前库存为--" + list.size());
                list.notify();
            }
        }    
    }

        public static void main(String[] args) {
            ProAndCon proAndCon = new ProAndCon();
            Producer producer = proAndCon.new Producer();
            Customer customer = proAndCon.new Customer();
            for (int i = 0; i < 10; i++) {
                Thread proThread = new Thread(producer);
                proThread.start();
                Thread comThread = new Thread(customer);
                comThread.start();
            }
        }
    }


输出结果如下:

    生产中,数量为--1
    消费量一个,当前库存为--0
    生产中,数量为--1
    消费量一个,当前库存为--0
    生产中,数量为--1
    消费量一个,当前库存为--0
    生产中,数量为--1
    消费量一个,当前库存为--0
    生产中,数量为--1
    消费量一个,当前库存为--0
    生产中,数量为--1
    生产中,数量为--2
    消费量一个,当前库存为--1
    消费量一个,当前库存为--0
    生产中,数量为--1
    生产中,数量为--2
    仓库已满,停止生产
    消费量一个,当前库存为--1
    消费量一个,当前库存为--0
    生产中,数量为--1
    消费量一个,当前库存为--0



                

            

最新评论:
2019?3?2?17:53:33 2019-03-03 01:53:35