zoukankan      html  css  js  c++  java
  • 线程池,多线程,线程异步,同步和死锁,Lock接口

     线程池

      线程池,其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。

    除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。线程池主要用来解决线程生命周期开销问题和资源不足问题。

     使用线程池方式--Runnable接口

    通常,线程池都是通过线程池工厂创建,再调用线程池中的方法获取线程,再通过线程去执行任务方法。

    Executors:线程池创建工厂类
        public static ExecutorService newFixedThreadPool(int nThreads):返回线程池对象
    ExecutorService:线程池类
        Future<?> submit(Runnable task):获取线程池中的某一个线程对象,并执行
    Future接口:用来记录线程任务执行完毕后产生的结果。线程池创建与使用

    使用线程池中线程对象的步骤:

    1.  创建线程池对象

    2.  创建Runnable接口子类对象

    3.  提交Runnable接口子类对象

    4.  关闭线程池

    package com.oracle.xiancheng;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class Xiancheng {
        public static void main(String[] args) {
            //创建线程池对象(从线程池工厂中获得)
            ExecutorService ec=Executors.newFixedThreadPool(2);
            //创建Runnable接口子类实例对象(创建任务对象)
            MyRunnable r = new MyRunnable();
            //    提交Runnable接口子类对象
            //线程池会选一条线程执行提交的任务
            ec.submit(r);
            //注意:submit方法调用结束后,程序并不终止,是因为线程池控制了线程的关闭。
            //又将使用完的线程又归还到了线程池中
            for(int i=0;i<50;i++){
                System.out.println("main..."+i);
            }
            ec.shutdown();//关闭线程池
        }
    }

    Runnable接口实现类

    package com.oracle.xiancheng;
    public class MyRunnable  implements Runnable {
    
        public void run() {
            for(int i=0;i<50;i++){
                System.out.println("runable..."+i);
            }
        }
    }

    使用线程池方式—Callable接口

    Callable接口:与Runnable接口功能相似,用来指定线程的任务。其中的call()方法,用来返回线程任务执行完毕后的结果,call方法可抛出异常。
    ExecutorService:线程池类
        <T> Future<T> submit(Callable<T> task):获取线程池中的某一个线程对象,并执行线程中的call()方法
    Future接口:用来记录线程任务执行完毕后产生的结果。线程池创建与使用

      使用线程池中线程对象的步骤:

      1. 创建线程池对象

      2. 创建Callable接口子类对象

      3. 提交Callable接口子类对象

      4.  关闭线程池

    Callable接口实现类,call方法可抛出异常、返回线程任务执行完毕后的结果

    package com.oracle.xiancheng;
    
    import java.util.concurrent.Callable;
    
    //Callable泛型就是你call的返回值类型
    public class MyCallable implements Callable<String> {
        public String call() throws Exception {
            
            return "这是call方法";
        }
    
    }

    测试类:

    package com.oracle.xiancheng;
    
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    public class demo01 {
    
        public static void main(String[] args) throws InterruptedException, ExecutionException {
            //获取线程池
            ExecutorService ec=Executors.newFixedThreadPool(2);
            //创建callable子类
            MyCallable mc=new MyCallable();
            //提交Callable子类
            Future<String> f=ec.submit(mc);
            String str=f.get();
            System.out.println(str);
            //关闭线程池
            ec.shutdown();
        }
    
    }

    异步计算0-100的和跟0-200的和

    package com.oracle.xiancheng;
    
    import java.util.concurrent.Callable;
    
    public class JiSuan  implements Callable<Integer>{
        private Integer a;
        public JiSuan(Integer a){
            this.a=a;
        }
        public Integer call(){
            int sum=0;
            for(int i=0;i<=a;i++){
                sum +=i;
            }
            System.out.println(sum);
            return sum;
        }
        
    }

    测试类:

    package com.oracle.xiancheng;
    
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    public class Yibu {
        //异步计算0-100的和跟0-200的和
        public static void main(String[] args) throws InterruptedException, ExecutionException {
            //获取线程池
    
            ExecutorService ec=Executors.newFixedThreadPool(2);
            //创建callable子类
            JiSuan js=new JiSuan(100);
            JiSuan js1=new JiSuan(200);
            //提交callable子类
            Future<Integer> f1=ec.submit(js);
            Future<Integer> f2=ec.submit(js1);
            /*//从future中获取返回值
            System.out.println(f1.get());
            System.out.println(f2.get());*/
            //关闭
            ec.shutdown();
        }
        
        
    }

     多线程

     线程安全

      电影院要卖票,我们模拟电影院的卖票过程。假设要播放的电影是 “功夫熊猫3”,本次电影的座位共100个(本场电影只能卖100张票)。

    我们来模拟电影院的售票窗口,实现多个窗口同时卖 “功夫熊猫3”这场电影票(多个窗口一起卖这100张票)

    需要窗口,采用线程对象来模拟;需要票,Runnable接口子类来模拟

    模拟票:

    public class Ticket implements Runnable {
        private int tickets=100;
       public void run(){
        //模拟卖票
    while(true){ if(tickets>0){
              //模拟选座
    try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"出售第"+tickets--+"张票"); } } } }

    测试类;

    package com.oracle.demo01;
    
    public class demo01 {
        public static void main(String[] args) {
            Ticket t=new Ticket();//创建票对象
            Thread t1=new Thread(t);
            Thread t2=new Thread(t);
            Thread t3=new Thread(t);
            t1.start();
            t2.start();
            t3.start();
            
        }
    }

    结果会出现重复的票,还有错误的票,0和-1问题

     线程同步(线程安全处理Synchronized)

    java中提供了线程同步机制,它能够解决上述的线程安全问题。

             线程同步的方式有两种:

     方式1:同步代码块

     方式2:同步方法

     同步代码块

    //同步代码块: 在代码块声明上 加上synchronized
    synchronized (锁对象) {
        //可能会产生线程安全问题的代码
    }

      同步代码块中的锁对象可以是任意的对象;但多个线程时,要使用同一个锁对象才能够保证线程安全。

    使用同步代码块,对电影院卖票案例中Ticket类进行如下代码修改:

    模拟出票

    public class Ticket implements Runnable {
        private int tickets=100;
        private Object lock = new Object();
        public void run(){
            while(true){
                
                synchronized (lock) {
                    if(tickets>0){
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        
                        System.out.println(Thread.currentThread().getName()+"出售第"+tickets--+"张票");
                    }else{
                        break;
                    }
                }
    
                
            }
        }

     同步方法

    //同步方法:在方法声明上加上synchronized
    public synchronized void method(){
           //可能会产生线程安全问题的代码
    }

    同步方法中的锁对象是 this

    使用同步方法,对电影院卖票案例中Ticket类进行如下代码修改:

    package com.oracle.demo01;
    
    public class Ticket implements Runnable {
        private int tickets=100;
        private Object lock = new Object();
        
        public void run() {
            //模拟卖票
            while(true){
                //同步方法
                method();
            }
        }
        
        //同步方法,锁对象this
         public synchronized void method(){
                if (tickets> 0) {
                    //模拟选坐的操作
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"出售第"+tickets--+"张票");
                }
          }
        
    
    
    }    
    //静态同步方法: 在方法声明上加上static synchronized
    public static synchronized void method(){
        //可能会产生线程安全问题的代码
    }

     静态同步方法中的锁对象是本类字节码对象  类名.class

    同步锁:对象锁,对象监视器

    同步是怎么保证安全性?

     因为同步中有锁,没有锁的线程,不能执行,只能等。

    StringBuilder比StringBuffer快

    原因:StringBuffer有同步关键字synchronized,安全性比StringBuilder高,但速度慢

      死锁

      同步锁使用的弊端:当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步。这时容易引发一种现象:程序出现无限等待,这种现象我们称为死锁。

    格式如:

    synchronzied(A锁){
        synchronized(B锁){
             
      }
    }

    定义锁对象类:

    package com.oracle.demo01;
    
    public class LockA {
    public final static LockA locka=new LockA();
    private LockA(){
        
    }
    }
    package com.oracle.demo01;
    
    public class LockB {
        public final static LockB lockb=new LockB();
        private LockB(){
            
        }
    }

    线程任务类:

    package com.oracle.demo01;
    
    public class DeadLock implements Runnable {
        private int i=0;
        
        public void run() {
            
            while(true){
                if(i%2==0){
                    //情况一
                    synchronized (LockA.locka){
                        System.out.println("IF......lockA");
                        synchronized (LockB.lockb){
                            System.out.println("IF......lockB");
                        }
                    }
                }else{
                    //情况二
                    synchronized (LockB.lockb){
                        System.out.println("else......lockB");
                        synchronized (LockA.locka){
                            System.out.println("else......lockA");
                        }
                    }
                }
                i++;
            }
        }
        
    }

    测试类:

    package com.oracle.demo01;
    
    public class TestDEADlock {
    
        public static void main(String[] args) {
            //创建线程任务类对象
            DeadLock dl=new DeadLock();
                //创建两个线程
            Thread t1=new Thread(dl);
            Thread t2=new Thread(dl);
               //开启线程
            t1.start();
            t2.start();
            
        }
    
    }

     Lock接口

      使用Lock接口,以及其中的lock()方法和unlock()方法替代同步,对电影院卖票案例中Ticket类进行如下代码修改:

    package com.oracle.demo01;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class NewTicket implements Runnable{
        private int tickets=100;
        //创建Lock锁对象
        private    Lock ck = new ReentrantLock();
            public void run(){
                while(true){
                    ck.lock();
                    if(tickets>0){
                        try {
                            Thread.sleep(10);
                            System.out.println(Thread.currentThread().getName()+"出售第"+tickets--+"张票");
        
                        } catch (InterruptedException e) {
                        
                            e.printStackTrace();
                        }finally{
                            ck.unlock();//释放锁
                        }
                    
                    }
                }
            }
    
    }
  • 相关阅读:
    php odbc连接 查询显示不完整问题
    php集成环境
    intent实现网页跳转
    夜神模拟器
    Android编程知识点3-Intent
    Android编程知识点2- 线性布局,随机数
    Android编程知识点1-Button,ListView
    数据存储和访问
    Android计时器
    组件通信2
  • 原文地址:https://www.cnblogs.com/lzw123-/p/9545658.html
Copyright © 2011-2022 走看看