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

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

* 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 future1 = pool.submit(new MyCallable(10));  // 将线程放进线程池中        Future future2 = pool.submit(new MyCallable(40));  // 将线程放进线程池中        Future 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 {     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

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!**

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值