SingleThread-Executton design pattern

SingleThread-Executto这个设计模式 是指在同一时刻只能有一个线程去访问共享资源 简单来说 SingleThread-Executton design pattern就是用排他的方式保证同一时刻只有一个线程访问共享资源

先看一个很简单的例子 就好像地铁过安检的时候 每次检查只能由一个人通过 下面用代码模仿这种情况

//定义一个门类 这里简单设定名字和地址 当名字和地址的第一个字母相同时就能通过这个门public class Gate {
    private String name = "";
    private String address = "";

    private int Count = 0;

    public synchronized void pass(String name, String address) {
        this.name = name;
        this.address = address;
        this.Count++;
        check();
    }

    public void check() {
        if (this.name.charAt(0) != this.address.charAt(0)) {
            System.out.println("**************BROKEN****" + toString());
        }
    }

    public String toString() {
        return "NO:" + Count + ":" + name + ":" + address;
    }
}

定义一个用户类

public class User extends Thread {
    private String name;
    private String address;
    private Gate gate;

    public User(String name, String address, Gate gate) {
        this.name = name;
        this.address = address;
        this.gate = gate;
    }

    @Override
    public void run() {
        System.out.println(this.name + "+" + this.address);
        while (true) {
            this.gate.pass(name, address);
        }
    }
}

接下来测试一下

public static void main(String[] args) {
        Gate gate = new Gate();
        User user1 = new User("baobao","beijing",gate);
        User user2 = new User("shangshang","shanghai",gate);
        User user3 = new User("guangguang","guangzhou",gate);
        user1.start();
        user2.start();
        user3.start();
    }

在这个例子中共享资源就是门的pass方法 若不对pass方法加synchronized关键字 就会出现名字与地址不一样也会通过门的情况 这就是线程的上下文轮转造成的数据不搭配现象 所以在这个设计模式的最重要的环节应该是找出共享资源并对它进行保护 下面看另一个例子,这种模式设计的不好就会出现死锁的情况

假设有两个人要吃面 但这两个人只有一对餐具 那么餐具就是这两个人的共享资源 这样很容易就会发生死锁的情况 比如A手持刀 等待B放下叉  B手持叉等待A放下刀

代码如下

public class Tableware { //简单定义一个餐具类
    private final String toolName;

    public Tableware(String toolName) {
        this.toolName = toolName;
    }

    @Override
    public String toString() {
        return "Tableware{" +
                "toolName=‘" + toolName + ‘\‘‘ +
                ‘}‘;
    }
}
public class EatNoodleThread extends Thread {
    private final String name;
    //左手餐具
    private final Tableware leftTool;
    //右手餐具
    private final Tableware rightTool;

    public EatNoodleThread(String name, Tableware leftTool, Tableware rightTool) {
        this.name = name;
        this.leftTool = leftTool;
        this.rightTool = rightTool;
    }

    @Override
    public void run() {
        while (true) {
            eat();
        }
    }

    private void eat() {
        synchronized (leftTool) {
            System.out.println(name + ":take up" + leftTool);
            synchronized (rightTool) {
                System.out.println(name + ":take up" + rightTool);
                System.out.println(name + ":is eatting now");
                System.out.println(name + ":put down " + rightTool);
            }
            System.out.println(name + ":put down" + leftTool);
        }
    }

}
public static void main(String[] args) {
        Tableware knife = new Tableware("knife");
        Tableware fork = new Tableware("fork");
        new EatNoodleThread("aaa", fork, knife).start();
        new EatNoodleThread("bbb", knife, fork).start();
    }

运行上面的程序 很快就会出现都阻塞住的情况 发生了死锁 而要解决这个死锁问题 可以将左餐具和右餐具结合在一起 将餐具看成一个共享变量而不是分成左餐具和右餐具 代码如下

public class EatNoodleThread extends Thread {
    private final String name;
    //将左餐具和右餐具都封装为一个餐具
    private final Tableware tableware;

    public EatNoodleThread(String name, Tableware tableware) {
        this.name = name;
        this.tableware = tableware;
    }

    @Override
    public void run() {
        while (true) {
            eat();
        }
    }

    private void eat() {
        synchronized (tableware) {
            System.out.println(name + ":take up " + tableware);
            System.out.println(name + ":is eatting now");
            System.out.println(name + ":put down " + tableware);
        }
    }

    public static void main(String[] args) {
        Tableware tableware = new Tableware("tableware");
        new EatNoodleThread("A", tableware).start();
        new EatNoodleThread("B", tableware).start();
    }
}

这样运行多久也都不会出现死锁的情况了

线程的安全是非常重要的 线程安全的类是指多个线程对这个类进行操作时 不会引起数据不一致的问题 这就是一个线程安全的类 所以确保线程安全非常重要的 但是在这个例子中线程安全用了synchronized关键字,这样排他性的设计同时也会牺牲性能 所以在设计的时候也要尽量减少synchronized的作用域

原文地址:https://www.cnblogs.com/luonote/p/10438255.html

时间: 2024-10-21 03:14:34

SingleThread-Executton design pattern的相关文章

DP什么意思 design pattern 设计模式

DP  design pattern 大话设计模式  中的DP 是设计模式的意思 设计模式的书 ,最经典最原始的就是 GOF 的<设计模式>了. 设计模式的书基本上大多是以这 20 多个模式分开讲.含<大话设计模式> 学了 OOL 写的程序基本上是 OB 的. 只有慢慢掌握了 DP 才能写出真正的 OO 程序. 思想 -> 设计原则 -> DP -> OOD

Head First Design Pattern 读书笔记(2) 观察者模式

Head First Design Pattern 读书笔记(2) Observer Pattern 观察者模式 Observer Pattern 类图 定义 观察者模式:在对象间定义一个一对多的关系,当其中一个的对象发生改变时,所有依赖于这个对象的对象(即观察者们)都会自动更新或做执行某些行为. 几个OO的原测 尽量以松耦合的方式处理对象间关系–>软件工程时候学的"高內聚,低耦合"的好处 关于观察者模式 被观察对象通知观察者可以使用推送的方式(类图中带参数的notifyActi

Design Pattern Singleton 单一模式

单一模式的几个注意点: 一) 设计单一模式,首先需要把构造函数给私有化了,不让外界访问,那么外界只能通过提供的函数获取一个新的类. 二) C++的单一模式,记得要在类外初始化一个类,否则或内存出错的. 三) 这个唯一的类必须是要静态的 程序: #ifndef _SINGLETON_H #define _SINGLETON_H #include <iostream> #include <string> using namespace std; class DuGuJiuJian {

Design Pattern 设计模式1 - Strategy 1

实现 : Defferent Heros attack Defferently. - 不同的英雄使用不用的招数 Strategy设计的思路: 基类A,更加小的基类B,新的继承类C: 1 从基类A中抽出一个更加小的基类B 2 利用这个更加小的基类B实现不同的效果 3 把这个更加小的基类B包含进基类A中去 4 新的继承类C只需要和基类A打交道,设计不同行为,不需要理会更加小的基类B #pragma once #ifndef _STRATEGY_HEROS_H #define _STRATEGY_HE

简单工厂设计模式(Simple Factory Design Pattern)

[引言]最近在Youtub上面看到一个讲解.net设计模式的视频,其中作者的一个理解让我印象很深刻:所谓的设计模式其实就是运用面向对象编程的思想来解决平时代码中的紧耦合,低扩展的问题.另外一点比较有见解的是,区分了设计模式(Design Pattern),结构模式(Architecture Pattern),架构类型(Architecture Style). 如下图所示 Design Pattern:是基于代码层面的,就是针对解决功能模块之间的问题而采用恰当的设计模式,比如依赖注入,简单工厂,适

Design Pattern —— Singleton

Design Pattern —— Singleton   强力推荐枚举和类级内部类方式实现单例模式 单例模式是开发中非常常用的一种模式,简单的说,我们希望一个类永远都只有一个对象. 主要有两个用途: 1.存储一些进程内共享的值(不是很推荐,大部分情况下还是应该用局部变量,互相传递值的方式) 2.任何时候都不变的操作 单例模式的实现目前已知的有五种: 1.饿汉式 2.懒汉式 3.双重验证 4.类级内部类 5.枚举 一.饿汉式 类加载时就创建好对象,以空间换时间.这样外部调用EagerSingle

Head First Design Pattern 读书笔记(1) 策略模式

Head First Design Pattern 读书笔记(1) Strategy Pattern 策略模式 这几天为了锻炼看英语文档的能力,开着有道硬着头皮看 <Head First Desgin Pattern>的原版书,顺便做下笔记,把里面提到的每个模式通过回忆的方式画出来复习并记下来总结下学习成果=.= 关于设计模式 使用设计模式是为了增强程序的复用性,拓展性,易维护性. 设计模式会增加程序代码的复杂度,并不是所有情况都必须使用设计模式,需要根据需求以及经验评估使用场景. 学习并掌握

State Design Pattern 状态设计模式

设置好内部状态,然后根据不同的函数作为行为模式,进行状态转换. 有点像Finite Automata算法,两者的思想是一样的. 会Finite Automata,那么这个设计模式就很容易了. #pragma once #include <stdlib.h> #include <math.h> #include <random> #include <time.h> enum STATES { FULLY_RENTED, WAITING, GOT_APPLICA

UML for Design Pattern

************************************************************************************* ************************************************************************************* ******************************************************************************

Head First 之 Design Pattern(二):Observer Pattern

观察者模式是最常用的设计模式之一,[对象之间多对一的依赖关系,当一个对象发生变化时,其会通知所有依赖它的对象].拿订阅报纸和发行报社打比方,报社采集到news制作新的报纸,派送给订阅的客户,以此把最新的消息告知客户.所以,出版社 + 订阅者 = 观察者模式. 这种一对多的关系,也即"一个"主题."多个"观察者能够使得观察者仅仅了解主题推送的消息但不知晓其中的细节,而主题握有观察者列表但不干涉到观察者的个人隐私.所以,它们之间相互有交互,但不紧密,不清楚对方的细节.改