zoukankan      html  css  js  c++  java
  • Java多线程(三)锁对象和线程池

    1:锁(Lock)

      1.1       java提供了一个锁的接口,这个锁同样可以达到同步代码块的功能,API文档上说使用锁比使用synchronized更加灵活。

      1.2       如何使用这个“锁”

        //1.创建一个所对象,我们可以理解为写一个synchronized代码块

        public static Lock lock = new ReentrantLock();//用lock的一个子类去创建

        //2.假设有某程序中使用两把锁,这两把锁是类似于synchronized里的锁

        //要使用到Condition类,中文:条件、情况、制约、限制的意思,在API文档总称之为“条件、条件列队或者条件变量”

                 public static Condition notFull = lock.newCondition();//Condition

                 public static Condition notEmpty = lock.newCondition();

      1.3       Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。(摘自文档,重点是最后一句)

      1.4       重要方法(Condition的):

          await():等候,调用此方法线程将释放锁,进入等待状态

          signal():中文:信号、发信号。调用此方法可以唤醒一个等待总的线程

          signalAll():唤醒所有在等待重点的线程

    1.5       使用Lock和Condition的生产和消费的代码。

      1 package com.java.lock;
      2 
      3 import java.util.ArrayList;
      4 import java.util.List;
      5 import java.util.concurrent.locks.Condition;
      6 import java.util.concurrent.locks.Lock;
      7 import java.util.concurrent.locks.ReentrantLock;
      8 
      9 public class ProduceCustomerDemo1 {
     10 
     11     public static void main(String[] args) {
     12         Produce p1 = new Produce();
     13         p1.setName("生产者1");
     14         Produce p2 = new Produce();
     15         p2.setName("生产者2");
     16         Produce p3 = new Produce();
     17         p3.setName("生产者3");
     18         Customer c1 = new Customer();
     19         c1.setName("消费者1");
     20         Customer c2 = new Customer();
     21         c2.setName("消费者2");
     22         Customer c3 = new Customer();
     23         c3.setName("消费者3");
     24         p1.start();
     25         p2.start();
     26         c1.start();
     27         c2.start();
     28         p3.start();
     29         c3.start();
     30     }
     31 }
     32 
     33 class MyLock {
     34     public static Lock lock = new ReentrantLock();
     35     public static Condition notFull = lock.newCondition();
     36     public static Condition notEmpty = lock.newCondition();
     37     public static int num;// 编号
     38     public static int sum;// 库存
     39     public static Object obj = new Object();
     40     public static List<Integer> list = new ArrayList<Integer>();
     41 }
     42 
     43 class Produce extends Thread {
     44     @Override
     45     public void run() {
     46         while (true) {
     47             //同步开始的标志,这里代替了synchronized
     48             MyLock.lock.lock();
     49             while (MyLock.sum >= 6) {// 在多个消费者操作这个数据时,每次都要判断而且是循环判断
     50                 try {
     51                     //notFull,调用await()方法进入等待状态,前提是sum》=6
     52                     MyLock.notFull.await();
     53                 } catch (InterruptedException e) {
     54                     e.printStackTrace();
     55                 }
     56             }
     57 
     58             MyLock.sum++;
     59             MyLock.num++;
     60             MyLock.list.add(MyLock.num);
     61             try {
     62                 Thread.sleep(100);
     63             } catch (InterruptedException e) {
     64                 e.printStackTrace();
     65             }
     66             System.out.println(Thread.currentThread().getName() + "生产了一个产品,编号:"
     67                     + MyLock.num + ",现有:" + MyLock.sum + "个");
     68             //调用signal()方法将等待中的线程唤醒,也可以使用signalAll()方法
     69             MyLock.notEmpty.signal();
     70             //同步结束的标志
     71             MyLock.lock.unlock();
     72         }
     73     }
     74 }
     75 
     76 class Customer extends Thread {
     77 
     78     @Override
     79     public void run() {
     80         while (true) {
     81             //同步代码块开始
     82             MyLock.lock.lock();
     83             while (MyLock.sum == 0) {
     84                 try {
     85                     //进入线程等待状态,前提是sum==0
     86                     MyLock.notEmpty.await();
     87                 } catch (InterruptedException e) {
     88                     e.printStackTrace();
     89                 }
     90             }
     91             int ran = (int) (Math.random() * MyLock.sum);
     92             MyLock.sum--;
     93             try {
     94                 Thread.sleep(100);
     95             } catch (InterruptedException e) {
     96                 e.printStackTrace();
     97             }
     98             int number = MyLock.list.remove(ran);
     99             System.out.println(Thread.currentThread().getName() + "消费了一个包子,编号:"
    100                     + number + ",现有:" + MyLock.sum + "个");
    101             //唤醒等待中的一个线程
    102             MyLock.notFull.signal();
    103             //同步代码块结束
    104             MyLock.lock.unlock();
    105         }
    106     }
    107 
    108 }
    Lock和Condition

    2:线程池.

             2.1:为什么会出现线程池。

                       线程的总时间=启动线程的时间t1+执行run方法的时间t2+销毁线程的时间t3。

                       如果t1+t3>t2时。这个时候应该减少启动线程和销毁线程的次数以节省时间。线程池可以解决这个问题。创建线程池,先启动固定个数的线程,让这些线程去执行任务,当一个线程执行完一个任务后,它会处于空闲状态,如果还有任务,它会继续执行其他的任务。当所有的任务执行完后,再销毁线程池中的线程。

          以上一段是网上找的,说的就是那么一回事,减少线程启动和提高线程运行的质量,也提高了运行效率。现实中这种情况也很常见嘛。一个饭店,一般都有一大桶饭的吧,当有顾客来了,就可以直接在饭桶里盛饭给顾客了,如果你没有一桶饭,那么每次有一个顾客来你都要单独帮他煮一份,万一顾客很多呢?这个饭店会有很多锅用来煮饭吗?即使煮好了碗,那顾客还有一碗,岂不是又要重新开锅帮他煮一碗?这样不合适吧,等饭的时间都比吃饭的时间要长咯。所以,饭店里准备着一大桶饭比较好。线程池就相当于这个饭桶,顾客相当于每个线程。锅其实也可以理解为资源或者内存吧。线程池(饭桶)提高了线程运行(顾客吃饭)的效率了,也节省了线程的开启关闭所占用的内存(锅)。虽然这个例子没有提到线程的关闭,但是这个例子就是这么一个意思。

                       只创建固定的线程。让它执行更多的任务。请往下看线程池的创建。

                       2.2相关的类:(一般也就是这两三个类就足够了

                                Executors(执行者):此包中所定义的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 类的工厂和实用方法。
                                ExecutorService:一个接口

                                ThreadPoolExecutor:实现了ExecutorServer接口的一个子类

                       2.3 线程池的创建以及使用线程池开启线程。

     1 import java.util.concurrent.ExecutorService;
     2 import java.util.concurrent.Executors;
     3 
     4 public class ThreadPoolDemo1 {
     5     public static void main(String[] args) {
     6         /*
     7          * 创建一个大小为 3 的线程池,newFixedThreadPool(int nThread)
     8          * 意思是这个线程池中最多同时可运行三个线程,如果要想执行其他线程应该等待线程池池有线程结束
     9          */
    10         ExecutorService executor = Executors.newFixedThreadPool(3);
    11         /*Produce p1 = new Produce();
    12         Customer c1 = new Customer();*/
    13         /*for(int i=0; i<3; i++){
    14             executor.execute(p1);
    15             executor.execute(c1);
    16         }*/
    17         //用循环来开启三个线程,也可以手动一个个开启
    18         for(int i=0; i<3; i++){
    19             executor.execute(new MyRunnable());
    20         }
    21         /*MyRunnable mr = new MyRunnable();
    22         executor.execute(mr);
    23         executor.execute(mr);
    24         executor.execute(mr);*/
    25         //线程执行完毕关闭线程池
    26         executor.shutdown();
    27     }
    28 }
    29 
    30 class MyRunnable implements Runnable{
    31 
    32     @Override
    33     public void run() {
    34         for(int i=0; i<10; i++){
    35             System.out.println(Thread.currentThread().getName()+":"+i);
    36         }
    37         
    38     }
    39     
    40 }
    View Code

    总结:以下是个人对线程的一下理解。

        线程可以让一个程序同时去执行多个任务,而不必等待前面的任务执行完才能执行下一个。好比车道:单条通道只能让一辆车通过,多条车道能让多辆车通过,通道就是线程,让车通过就是任务,让车通过的速度哪个快就很明显了(前提是车的数量和车速不能相差太多)。线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源的使用效率从而提高了系统的效率。

        当多线程操作同一个数据时就会发生线程安全问题,解决的方法就是实现线程的同步,同步有两种方法,1:使用synchronized(同步)关键字,synchronized还可以分为synchronized方法和synchronized代码块;2:使用Lock,配合Condition对象。同步是解决的安全性问题,但是同时也带来了两个问题。1:执行效率下降;2:同步死锁。死锁在同步嵌套(同步中又有同步)发生。

        线程太多,开启和关闭用的时间就多了,为了提高线程运行的效率更高,用到了线程池。线程池使得线程的开启和关闭的时间大大减少,提高了线程运行效率。

       

  • 相关阅读:
    Json对象与Json字符串互转(4种转换方式)
    Web.config配置文件详解
    jQuery BlockUI Plugin Demo 6(Options)
    jQuery BlockUI Plugin Demo 5(Simple Modal Dialog Example)
    jQuery BlockUI Plugin Demo 4(Element Blocking Examples)
    jQuery BlockUI Plugin Demo 3(Page Blocking Examples)
    jQuery BlockUI Plugin Demo 2
    <configSections> 位置引起的错误
    关于jQuery的cookies插件2.2.0版设置过期时间的说明
    jQuery插件—获取URL参数
  • 原文地址:https://www.cnblogs.com/xinge1993/p/4738149.html
Copyright © 2011-2022 走看看