Java 基础篇:第二十章:多线程和设计模式

主要内容:

  1. 单例模式及应用实例

2、多线程的通信

3、线程的五种状态

4、简单工厂设计模式

5、工厂方法模式

ArrayList:增改快,查询慢。线程不安全(实现不是同步的,如果有一个线程对某个实例进行了修改,其他线程不知道,其他也可同时修改)。

HashMap:线程不安全。

StringBuilder:将 StringBuilder 的实例用于多个线程是不安全的。

HashSet:线程不安全。

StringBuffer、Vector、Hashtable:线程安全的。

一、多线程的通信:

1.1 线程的五种状态

新建:创建线程对象。

就绪:线程对象启动了,但是还没有获取到CPU的执行权。

运行:获取到CPU的执行权。

阻塞:已经准备就绪的、但是还没有执行权。

死亡:代码执行完毕,线程消亡。

1.2 两个线程之间的通信:

1、什么时候需要通信:

如果是多个线程并发执行的时候,在默认情况下CPU是随机切换线程。如果我们希望有规律低执行,就需要使用通信。

2、如何通信?

如果希望线程等待,就调用wait()方法;如果希望唤醒等待的线程,就调用notify()方法。这两个方法必须在同步代码块中执行,并且使用同步代码锁对象来调用。

Object类中的wait(): 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。

notify() :唤醒在此对象监视器上等待的单个线程。

public class Demo01_DoubleThread {

    /*

     * 两个线程的通信

     */

    public static void main(String[] args) {

       final Print print = new Print();

       new Thread() {

           public void run() {

              while (true) {

                  try {

                     print.print01();

                  } catch (InterruptedException e) {

                     e.printStackTrace();

                  }

              }

           }

       }.start();

       new Thread() {

           public void run() {

              while (true) {

                  try {

                     print.print02();

                  } catch (InterruptedException e) {

                     e.printStackTrace();

                  }

              }

           }

       }.start();

    }

}

class Print {

    private int flag = 1;

    public void print01() throws InterruptedException {

       synchronized (this) {

           if (flag != 1) {

              this.wait();   // 当前线程等待

           }

           System.out.print("坚");

           System.out.print("持");

           System.out.print("努");

           System.out.print("力");

           System.out.print("吧");

           System.out.print("\r\n");

           flag = 2;

           this.notify();   // 随机唤醒单个等待的线程

       }

    }

    public void print02() throws InterruptedException {

       synchronized (this) {

           if (flag != 2) {

              this.wait();

           }

           System.out.print("J");

           System.out.print("U");

           System.out.print("S");

           System.out.print("T");

           System.out.print("\r\n");

           flag = 1;

           this.notify();

       }

    }

}

1.3 多个线程之间的通信(JDK1.5之前):

* notify()方法是随机唤醒一个线程

* notifyAll()方法是唤醒所有线程

* JDK5之前无法唤醒指定的一个线程

* 如果多个线程之间通信, 需要使用notifyAll()通知所有线程, while来反复判断条件。

public class Demo02_MultiThread {

    /*

     * 三个线程的通信

     * notifyAll():唤醒在此对象监视器上等待的所有线程。

     */

    public static void main(String[] args) {

       final Printer pt = new Printer();

       new Thread() {

           public void run() {

              while (true) {

                  try {

                     pt.print01();

                  } catch (InterruptedException e) {

                     e.printStackTrace();

                  }

              }

           }

       }.start();

       new Thread() {

           public void run() {

              while (true) {

                  try {

                     pt.print02();

                  } catch (InterruptedException e) {

                     e.printStackTrace();

                  }

              }

           }

       }.start();

       new Thread() {

           public void run() {

              while (true) {

                  try {

                     pt.print03();

                  } catch (InterruptedException e) {

                     e.printStackTrace();

                  }

              }

           }

       }.start();

    }

}

class Printer {

    private int flag = 1;

    public void print01() throws InterruptedException {

       synchronized (this) {

           while (flag != 1) {

              this.wait();

           }

           System.out.print("1....坚");

           System.out.print("持");

           System.out.print("努");

           System.out.print("力");

           System.out.print("吧");

           System.out.print("\r\n");   

           flag = 2;

           this.notifyAll();

       }

    }

    public void print02() throws InterruptedException {

       synchronized (this) {

           while (flag != 2) {

              this.wait();

           }

           System.out.print("2....J");

           System.out.print("U");

           System.out.print("S");

           System.out.print("T");

           System.out.print("\r\n");  

           flag = 3;

           this.notifyAll();

       }

    }

    public void print03() throws InterruptedException {

       synchronized (this) {

           while (flag != 3) {

              this.wait();

           }

           System.out.print("3....P");

           System.out.print("e");

           System.out.print("a");

           System.out.print("c");

           System.out.print("e");

           System.out.print("\r\n");

           flag = 1;

           this.notifyAll();

       }

    }

}

1.4 多个线程之间的通信(JDk1.5新特性):

1.同步

         * 使用ReentrantLock类的lock()和unlock()方法进行同步

一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。

public Condition newCondition():返回用来与此 Lock 实例一起使用的 Condition 实例。

Condition接口:
                            await():造成当前线程在接到信号或被中断之前一直处于等待状态。

signal():唤醒一个等待线程。

2.通信

         * 使用ReentrantLock类的newCondition()方法可以获取Condition对象

         * 需要等待的时候使用Condition的await()方法, 唤醒的时候用signal()方法

         * 不同的线程使用不同的Condition, 这样就能区分唤醒的时候找哪个线程了

public class Demo02_MultiThread {

    /*

     * 三个线程的通信

     * ReentrantLock/Condition,这是JDK1.5之后版本的新特新

     */

    public static void main(String[] args) {

       final Printer3 pt = new Printer3();

       new Thread() {

           public void run() {

              while (true) {

                  try {

                     pt.print01();

                  } catch (InterruptedException e) {

                     e.printStackTrace();

                  }

              }

           }

       }.start();

       new Thread() {

           public void run() {

              while (true) {

                  try {

                     pt.print02();

                  } catch (InterruptedException e) {

                     e.printStackTrace();

                  }

              }

           }

       }.start();

       new Thread() {

           public void run() {

              while (true) {

                  try {

                     pt.print03();

                  } catch (InterruptedException e) {

                     e.printStackTrace();

                  }

              }

           }

       }.start();

    }

}

class Printer3 {

    private ReentrantLock reentrantLock = new ReentrantLock();  // 创建一个互斥锁对象

    private Condition condition1 = reentrantLock.newCondition();  // 获取的一个Condition对象

    private Condition condition2 = reentrantLock.newCondition();  // 获取的一个Condition对象

    private Condition condition3 = reentrantLock.newCondition();  // 获取的一个Condition对象

    private int flag = 1;

    public void print01() throws InterruptedException {

       reentrantLock.lock();   // 获取锁

       if (flag != 1) {

           condition1.await();   // 等待

       }

       System.out.print("1....坚");

       System.out.print("持");

       System.out.print("努");

       System.out.print("力");

       System.out.print("吧");

       System.out.print("\r\n");

       flag = 2;

       condition2.signal();  // 唤醒

       reentrantLock.unlock();   // 释放锁

    }

    public void print02() throws InterruptedException {

       reentrantLock.lock();

       if (flag != 2) {

           condition2.await();

       }

       System.out.print("2....J");

       System.out.print("U");

       System.out.print("S");

       System.out.print("T");

       System.out.print("\r\n");

       flag = 3;

       condition3.signal();

       reentrantLock.unlock();

    }

    public void print03() throws InterruptedException {

       reentrantLock.lock();

       if (flag != 3) {

           condition3.await();

       }

       System.out.print("3....P");

       System.out.print("e");

       System.out.print("a");

       System.out.print("c");

       System.out.print("e");

       System.out.print("\r\n");

       flag = 1;

       condition1.signal();

       reentrantLock.unlock();

    }

}

二、多线程的高级应用:

2.1 线程组:

public class Demo04_ThreadGroup {

    /**

     * ThreadGroup线程组

     */

    public static void main(String[] args) {

       // demo01();

       ThreadGroup group = new ThreadGroup("我是一个WeChat线程组");

       MyRun mr = new MyRun();

       Thread thread1 = new Thread(group, mr, "WeChat-张三");

       Thread thread2 = new Thread(group, mr, "WeChat-李四");

       group.setDaemon(true);  // 把整个线程组设置为守护线程

       System.out.println(thread1.getThreadGroup().getName());   // 获取线程thread1所在线程组的名字

       System.out.println(thread2.getThreadGroup().getName());   // 获取线程thread2所在线程组的名字

    }

    private static void demo01() {

       MyRun mr = new MyRun();

       Thread thread1 = new Thread(mr, "WeChat-张三");

       Thread thread2 = new Thread(mr, "WeChat-李四");

       // 直接放在主线程中的线程,默认会分在main线程组中

       ThreadGroup group1 = thread1.getThreadGroup();

       ThreadGroup group2 = thread2.getThreadGroup();

       System.out.println(group1.getName());

       System.out.println(group2.getName());

    }

}

class MyRun implements Runnable {

    @Override

    public void run() {

       for (int i = 0; i < 1000; i++) {

           System.out.println(Thread.currentThread().getName() + "---------"

                  + i);

       }

    }

}

2.2 线程池:

程序启动一个新的线程成本比较高的,因为它涉及到与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是程序中需要创建大量的生存期短线程的时候,更应该考虑使用线程池。线程池中的线程在程序代码结束之后,并不会死亡,而是再次回到线程池,称为空闲状态,等待下一个对象来使用。JDK1.5版本起不需要手动写,由Java内置支持。

public class Demo05_Executor {

    /**

     * 线程池

     */

    public static void main(String[] args) {

       ExecutorService pool = Executors.newFixedThreadPool(2);   // 创建线程池

       // 将线程放入线程池,会启动线程池

       pool.submit(new MyRunnable());

       pool.submit(new MyRunnable());

       pool.shutdown();   // 关闭线程池

    }

}

class MyRunnable implements Runnable {

    @Override

    public void run() {

       for (int i = 0; i < 1000; i++) {

           System.out.println(Thread.currentThread().getName() + "---------"

                  + i);

       }

    }

}

2.3 多线程的实现方式(实现Callable接口):

public class Demo06_Callable {

    /**

     * Callable接口——线程的第三种实现方式

     */

    public static void main(String[] args) throws InterruptedException,

           ExecutionException {

       ExecutorService pool = Executors.newFixedThreadPool(3);   // 创建一个线程池

       Future<Integer> future1 = pool.submit(new MyCallable(10));  // 将线程放进线程池中

       Future<Integer> future2 = pool.submit(new MyCallable(40));  // 将线程放进线程池中

       Future<Integer> future3 = pool.submit(new MyCallable(100));  // 将线程放进线程池中

       System.out.println(future1.get());

       System.out.println(future2.get());

       System.out.println(future3.get());

       pool.shutdown();

    }

}

class MyCallable implements Callable<Integer> {

    private int number;

    public MyCallable() {

    }

    public MyCallable(int number) {

       this.number = number;

    }

    @Override

    public Integer call() throws Exception {   // 求1到指定整数之间的全部整数之和

       int sum = 0;

       for (int i = 1; i <= number; i++) {

           sum += i;

       }

       return sum;

    }

}

三、常见设计模式:

3.1单例设计模式:

3.1.1 概述:

单例设计模式:保证类在内存中只有一个实例对象。比如BBS论坛中访客(当前在线人数)的实时统计,必须保证存储总数的对象只能是一个。

如何保证类在内存中只有一个对象?

控制类的创建,不让其他的类来创建本类对象——使用private修饰构造方法。

在本类中定义一个本类的对象。

对外提供一个公共的访问方法。

3.1.2 实现方式:

public class Demo01_Singleton {

    /**

     * 单例模式的两种实现:饿汉和懒汉

     */

    public static void main(String[] args) {

       Visitor visitor1 = Visitor.getInstance();

       Visitor visitor2 = Visitor.getInstance();

       System.out.println(visitor1 == visitor2);

    }

}

/*

 * 饿汉模式和懒汉模式的区别:

 * 1、饿汉模式是以空间换时间,懒汉模式是以时间换空间

 * 2、在多线程访问时,饿汉模式一定不会创建多个对象的;懒汉模式有可能会创建出多个对象

 * 3、开发时一般是使用饿汉模式,面试笔试考懒汉

 */

class Visitor {   // 懒汉模式

    // 1.私有的构造方法,其他的类不能访问该构造方法

    private Visitor() {

    }

    // 2.声明一个引用

    private static Visitor visitor;

    // 3.对外提供公共的访问方法

    public static Visitor getInstance() {  // 获取实例

       if (visitor == null) {

           visitor = new Visitor();  // 线程1等待,线程2会创建一个成功了

       }

       return visitor;

    }

}

// class Visitor { // 饿汉模式

// // 1.私有的构造方法,其他的类不能访问该构造方法

// private Visitor() {

// }

//

// // 2.创建一个本类对象

// private static Visitor visitor = new Visitor();

//

// // 3.对外提供公共的访问方法

// public static Visitor getInstance() { // 获取实例

// return visitor;

// }

// }

3.1.3 Runtime类:

Ctrl+Shift+T:查看源码。

每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。可以通过 getRuntime 方法获取当前运行时对象。应用程序不能创建自己的 Runtime 类实例。

public class Demo02_Runtime {

    /**

     * Runtime类的定义采用饿汉模式,与当前的运行环境相连接

     */

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

       Runtime time = Runtime.getRuntime();   // 获取运行时对象

       time.exec("shutdown -s -t 300");   // 300s之后立即关机

       time.exec("shutdown -a");   // 中止系统关机

    }

}

3.1.4 定时器类:

public class Demo03_Timer {

    /**

     * 单例模式实现的定时器

     */

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

       Timer timer = new Timer();   // 创建一个定时器对象

       // 在指定时间安排指定任务

       // Date的构造器中:

       // year - 减 1900 的年份。

       // month - 0-11 之间的月份。

       // date - 一月中 1-31 之间的某一天。

       // hrs - 0-23 之间的小时数。

       // min - 0-59 之间的分钟数。

       // sec - 0-59 之间的秒数。

       // 第一参数是安排的任务,第二个参数是执行的时间,第三个参数是过多久之后再重复执行

       timer.schedule(new MyTimerTask(), new Date(117, 6, 28, 16, 39, 10),

              3000);  // 2017-07-28-16:35:00

       while (true) {

           Thread.sleep(1000);

           System.out.println("当前时间为:" + new Date());

       }

    }

}

class MyTimerTask extends TimerTask {

    @Override

    public void run() {

       System.out.println("你应该被自己帅醒了!!!!");

    }

}

3.2 简单工厂设计模式:

简单工厂设计模式,又被称为静态工厂方法模式,它定义一个具体的工厂类负责创建一些实例对象。

优点:客户端不需要负责对象的创建,从而明确了各个类的职责。

缺点:这个静态工厂类负责所有对象的创建,如果有新的对象增加,或者某些对象的创建方式不同,就需要修改工厂类,不利于后期的维护。

3.3 工厂方法模式:

工厂方法模式中,抽象工厂类负责定义创建对象的接口,具体的对象创建工作由继承抽象工厂的具体类实现。

优点:客户端不需要负责对象的创建,从而明确了各个类的职责;如果有新的对象的增加,只需要增加一个具体的类和具体的工厂类即可,不影响原有的代码,后期维护容易,增强了系统的扩展性。

缺点:需要额外的编写代码,增加了工作量。

Struts2

Hibernate3框架

org.hibernate.SessionFactory

Spring

SpringMVC

MyBatis(Ibatis)

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逼哥很疯狂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值