Java=线程池,死锁,线程状态

线程池

死锁

线程的状态

定时器

一。线程池

使用线程时,我们会临时创建一个线程,然后启动,而线程的创建,以及线程使用完毕之后的销毁,都是需要消耗性能的.
思考: 能不能事先把线程对象创建好,然后需要用到时直接把创建好的线程拿过来使用,
        使用完毕,重新归还,等待下次继续使用???   
      能! 其实这就是线程池的思想  

线程池: 其实就是一个保存多个线程对象的容器,其中的线程可以反复使用,节省了创建和销毁的所消耗性能

使用:

线程池的顶层接口:
	java.util.concurrent.Executor
线程池的子接口:
	 java.util.concurrent.ExecutorService
线程池有一个工具类:其作用是帮助我们创建一个线程池对象
	java.util.concurrent.Executors
工具类中静态方法:创建一个线程池对象
    public static ExecutorService newFixedThreadPool(int nThreads);
												创建一个具有指定线程个数的线程池对象
                                                    
如何向线程池中提交任务呢??     
    调用ExecutorService接口中规定的方法:
	public Future<?> submit(Runnable task); 向线程池中提交无返回值的任务
    public Future<T> submit(Callable<T> task);向线程池中提交有返回值的任务,返回Future类型,
												表示返回了封装线程执行完毕之后结果的那个对象  

效果:

public class TestThreadPoolDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //1.创建一个线程池,使用多态接收
        ExecutorService service = Executors.newFixedThreadPool(3);

        //2.向线程池中提交 无返回值 任务
//        for (int i = 0; i < 10; i++) {
//            service.submit(new Runnable() {
//                @Override
//                public void run() {
//                    System.out.println(Thread.currentThread().getName()+"执行了....");//
//                }
//            });
//        }
        //3.向线程池中提交 有返回值 任务
        //提交
        Future<Integer> future = service.submit(new Callable<Integer>(){
            @Override
            public Integer call() {
                //求1-100的和任务
                int sum = 0;
                for (int i = 1; i < 101; i++) {
                    sum+=i;
                }
                return sum;
            }
        });

        //从future中取出结果
        Integer result = future.get();// 因为方法具有阻塞功能,会等待任务直接完毕之后再返回结果
        System.out.println("result = " + result);


        //如果想要整个进程停止
        //那么需要关闭线程池
        service.shutdown();
    }
}

、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

Executor框架

什么是Executor框架?

我们知道线程池就是线程的集合,线程池集中管理线程,以实现线程的重用,降低资源消耗,提高响应速度等。线程用于执行异步任务,单个的线程既是工作单元也是执行机制,从JDK1.5开始,为了把工作单元与执行机制分离开,Executor框架诞生了,他是一个用于统一创建与运行的接口。Executor框架实现的就是线程池的功能。

扫描二维码关注公众号,回复: 10351600 查看本文章

Executor框架结构图解

1、Executor框架包括3大部分:

(1)任务。也就是工作单元,包括被执行任务需要实现的接口:Runnable接口或者Callable接口;

(2)任务的执行。也就是把任务分派给多个线程的执行机制,包括Executor接口及继承自Executor接口的ExecutorService接口。

(3)异步计算的结果。包括Future接口及实现了Future接口的FutureTask类。

Executor框架的成员及其关系可以用一下的关系图表示:

2、Executor框架的使用示意图

(1)创建Runnable并重写run()方法或者Callable对象并重写call()方法:

    class callableTest implements Callable<String >{
                @Override
                public String call() {
                    try{
                        String a = "return String";
                        return a;
                    }
                    catch(Exception e){
                        e.printStackTrace();
                        return "exception";
                    }
                }
            }

 

二。死锁

死锁,在多线程中有多把锁,最后导致所有的锁都在等待,造成的现象称为死锁

产生死锁的条件

至少有两个线程

至少有两个锁对象

必须有synchronized的嵌套

死锁现象:

public class TestDeadLock {
    public static void main(String[] args) {
        //1.先创建2把锁对象
        Object obj1 = new Object();
        Object obj2 = new Object();

        //2.再创建2个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                //3.必须有synchronized嵌套
                while (true){
                    synchronized (obj1){
                        System.out.println("线程1抢到了obj1,还需要抢obj2..");
                        synchronized (obj2){
                            System.out.println("线程1抢到了obj2,那么可以执行了...");
                            System.out.println(Thread.currentThread().getName()+"执行了..");
                        }
                    }
                }

            }
        }).start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                //4.必须有synchronized嵌套
                while (true){
                    synchronized (obj2){
                        System.out.println("线程2抢到obj2,还需要抢obj1...");
                        synchronized (obj1){
                            System.out.println("线程2抢到obj1,那么可以执行了...");
                            System.out.println(Thread.currentThread().getName()+"执行了....");
                        }
                    }
                }

            }
        }).start();
    }
}

注意:如果出现了死锁怎么办??
    	无解!! 我们只能事先尽量避免死锁

三,线程的状态

线程的六种状态:

新建状态:New

刚刚创建的且未调用start方法的线程

可运行状态 Runnable

处于新建状态的线程调用了start方法之后,注意:只有新建状态的线程才能调用start()

受(锁)阻塞状态Blocked

线程运行的过程中遇到了同步方法,同步代码块,Lock锁,但是锁已经被其他线程持有了

限时等待状态Timed_waiting

线程执行到代码Thread.sleep();线程就处于限时等待状态

无限等待状态Waiting

--线程如何进入waiting无线等待状态

a该线程必须先持有锁对象

b调用锁对象的wait方法,进入无限等待

c进入无限等待之前,会自动释放锁对象

--其他线程如何唤醒waiting状态的线程

a其他线程先持有锁对象,就是进入无限等待线程释放的那个锁对象

b调用锁对象的notify方法,唤醒无限等待的线程

c被唤醒的无限等待线程,先进入锁阻塞,直到再次持有锁对象才能进入可运行状态

消亡状态Terminated

当线程的任务执行完毕,此时线程处于消亡状态

注意:处于消亡状态的线程,不能再调用start方法起死回生

四。等待唤醒机制

等待唤醒机制(Wait和Notify)

public class TestWaitingDemo {
    public static void main(String[] args) throws InterruptedException {
        //如何让一个线程进入 无限等待
        //1.创建一把锁对象
        Object obj = new Object();

        //2.创建一个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (obj){
                    //1.进入这个代码块,说明线程A抢到锁了
                    System.out.println("线程A持有锁对象obj...");
                    //2.进入无限等待
                    System.out.println("线程A进入了无限等待了...");
                    try {
                        obj.wait(); //进入无限等待之前会自动释放锁对象
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //3.醒来后会继续执行
                    System.out.println("线程A从无限等待中醒来了...");
                }
            }
        }).start();

        Thread.sleep(2000);
        //3.再来一个线程,负责唤醒线程A
        new Thread(new Runnable() {
            @Override
            public void run() {
                //1.持有相同的锁对象
                synchronized (obj){
                    System.out.println("线程B持有锁对象obj...");
                    System.out.println("线程B唤醒了线程A....");
                    //2.调用锁对象的notify方法
                    obj.notify();
                    //3.线程执行一下任务
                    for (int i = 0; i < 10; i++) {
                        System.out.println(i);
                    }
                }
            }
        }).start();
    }
}

注意:
	a.只有线程进入了无限等待,其他线程调用锁对象.notify()才有作用,否则也可以调用,但是没有任何作用(不会报错)
    b.锁对象.notify方法只能唤醒一个线程,具体是哪一个是随机的  
        
    c.锁对象.notifyAll方法可以唤醒多个线程,谁抢到锁谁执行     

2.生产者和消费者问题:

需求

需求:
    生产者消费者案例
    需要两个线程: 线程1包子铺线程,负责生产包子,线程2吃货线程,负责吃包子
        如果没有包子,那么吃货线程等待,包子铺线程执行(做包子),做完之后唤醒吃货线程
        如果有包子,那么包子铺线程等待,吃货线程执行(吃包子),吃饭之后唤醒包子铺线程

public class TestDemo {
    public static void main(String[] args) {
        //1.创建一个集合
        ArrayList<String> arr = new ArrayList<String>();
        arr.add("包子");
        //2.创建一个锁
        Object obj = new Object();
        //3.线程1:包子铺线程
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    //a.同步代码块
                    synchronized (obj){
                        //b.判断
                        if (arr.size() > 0) {
                            //c.有包子,那么无限等待
                            try {
                                System.out.println("包子铺发现有包子,进入无限等待...");
                                obj.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        //d.没有包子,做包子
                        System.out.println("包子铺做了一个包子....");
                        arr.add("包子");
                        //e.通知吃货线程
                        System.out.println("包子铺做完包子,唤醒吃货...");
                        obj.notify();
                    }
                }
            }
        });

        //4.线程2:吃货线程
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    //a.同步代码块
                    synchronized (obj){
                        //b.判断
                        if (arr.size() == 0) {
                            try {
                                System.out.println("吃货发现没有包子,进入无限等待....");
                                obj.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        //c.有包子,吃包子
                        System.out.println("吃货吃了包子...");
                        arr.remove(0);
                        //d.通知包子铺做
                        System.out.println("吃货吃完包子,唤醒包子铺...");
                        obj.notify();
                    }
                }
            }
        });
        //5.启动
        t1.start();
        t2.start();
    }
}

五。定时器

可以让某个线程在某个时间做指定的任务,或者某个时间以后指定的时间间隔中反复做某个任务!!

public Timer():构造一个定时器

public void schedule(TimerTask task, long delay); //在指定的时间之后执行指定的任务

public void schedule(TimerTask task, long delay, long period);//在指定的时间之后开始周期性的执行任务,周期的时间间隔是period

public void schedule(TimerTask task, Date time);//在指定的时间点执行指定的任务
public void schedule(TimerTask task, Date firstTime,long period);//在指定的时间点第一次执行任务,继续周期性执行任务,周期的时间间隔period

-------

public class TestTimer {
    public static void main(String[] args) {
        //1.创建一个定时器
        Timer timer = new Timer();
        //2.任务1
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("任务1执行...");
            }
        },2000);

        //3.任务2
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("任务2执行...");
            }
        },2000,1000);

        //4.任务3
        Calendar cc = Calendar.getInstance();
        cc.add(Calendar.SECOND,5);

        Date date = cc.getTime();

        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("任务3执行了...");
            }
        },date);

        //5.任务4
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("任务4执行...");
            }
        },date,1000);
    }
}

==============

public static void main(String[] args) throws  Exception {

        ExecutorService es = Executors.newFixedThreadPool(3);
        Callable<Double> cal = new Callable<Double>() {
            @Override
            public Double call() throws Exception {
                Random ran = new Random();
                Double sum = 0.0;
                for (int i=0;i<10;i++){
                    Double rom =ran.nextDouble()*99+1;
                    sum = sum+rom;
                }
                return sum/10;
            }
        };
        Double avg1 =  es.submit(cal).get();
        Double avg2 =  es.submit(cal).get();
        Double avg3 =  es.submit(cal).get();
        Double avg = (avg1+avg2+avg3)/3;
        System.out.println( String.format("==第一个线程的平均数为:%.2f",avg1));
        System.out.println(String.format("==第二个线程的平均数为:%.2f",avg2));
        System.out.println(String.format("==第三个线程的平均数为:%.2f",avg3));
        System.out.println(String.format("==三个线程的平均数的平均数为:%.2f",avg));

    }

参考博客:

https://blog.csdn.net/tongdanping/article/details/79604637

发布了117 篇原创文章 · 获赞 20 · 访问量 27万+

猜你喜欢

转载自blog.csdn.net/u010581811/article/details/104948443