zoukankan      html  css  js  c++  java
  • 线程下

    10.4:线程互斥

    在并发程序设计中已经被研究并得到解决.对多线程共享的资源或数据称为临界资源,而把每一个线程中访问临界资源的那一段代码称为临界代码.通过为临界带买段设置信号灯,就可以保证资源的完整性,从而安全地访问共享资源.

    为了实现这种机制,Java语言提供了以下两方面的支持

    为每个对象设置了一个互斥锁标记.该标记保证在任何时候,只能有一个线程有该互斥锁,其他线程如果需要获得互斥锁,必须等待当前拥有该锁的线程将其释放.该对象称为互斥对象.

    为了配合使用对象的互斥锁,Java语言提供了保留字synchronized.其基本用法如下:

    Synchronized(互斥对象){

    临界代码

    }

    当一个线程执行到该行代码时,首先检测该互斥对象的互斥锁.如果该互斥锁没有被占用,则该线程将获得该互斥锁,并执行临界代码,直到执行完毕并释放互斥锁;

    可以看出,任意一个对象都可以作为信息灯,从而解决上面的问题,首先定义一个互斥对象类,作为信号灯.由于该对象只作为信号量使用,所以并不需要为它定义其他方法.

    public class AccountThread extends Thread

    {

    public static void main(String[] args)

    {

    Account account = new Account(100);

    Semaphore semaphore = new Semaphore();

    AccountThread at1 = new AccountThread(account, 1000, semaphore);

    AccountThread at2 = new AccountThread(account, 0, semaphore);

    at1.start();

    at2.start();

    }

    Account account;

    int delay;

    Semaphore semaphore;

    // 构造方法

    public AccountThread(Account account, int delay, Semaphore semaphore)

    {

    this.account = account;

    this.delay = delay;

    this.semaphore = semaphore;

    }

    @Override

    public void run()

    {

    synchronized (this.semaphore)

    {

    if (this.account.balance >= 100)

    {

    try

    {

    // 延迟

    sleep(this.delay);

    // 模拟取钱100

    this.account.balance = this.account.balance - 100;

    System.out.println("withdraw 100 successful!!!");

    }

    catch (InterruptedException e)

    {

    e.printStackTrace();

    }

    }

    else

    {

    System.out.println("withdraw failed!!!");

    }}}}

    // 定义一个类,利用其对象作为互斥信号灯

    class Semaphore{}

    10.5:线程同步

    在实际应用中,多个线程之间不仅需要互斥机制来保证对共享数据的完整性,而且有时需要多个线程之间的相互合作,一个典型的应用称为 生产者-消费者模型

    1:生产者负责产品,并将其保存到仓库中

    2:消费者从仓库中获取产品

    3:由于库房容量有限,因此只有当库房还有空间时,生产者才可以将产品存入库房,否则只能等待

    4:只有库房中存在满足数量的产品时,消费者才可以取走产品否则只能等待

    Java语言为互斥对象提供了两个方法:一个是wait(),一个是notify() 这两个方法必须同时使用

    wait()方法的语义是:当一个线程执行了该方法后,则该线程进入堵塞状态,同时让出同步对象的互斥锁,并自动进入互斥对象的等待队列

    Notify()方法的语义是:当一个线程执行了该方法后,则拥有该方法的互斥对象的等待队列中的第一个线程被唤醒,同时自动获得该互斥对象的互斥锁,并进入就绪状态等待调度

    10.6 线程通信

    线程之间的通信问题是指线程之间互相传递信息,这些信息包括数据,控制指令.线程至之间通过管道进行通信

    管道的特点?

    1:管道是单向的.一个线程充当发送者,另一个线程充当接受者.如果需要建立双向通信,可以通过建立多个管道解决

    2:管道通信是面向连接的.因此在程序设计中,一方线程必须建立起对应的端点,由另一方线程来建立连接.

    3:官道中的通信是严格按照发送的顺序进行传送的.

    10.7 线程死锁

    线程死锁是并发程序设计中可能遇到的问题之一.它是指程序运行过程中,多个线程竞争共享资源时可能出现的一种系统状态.

    出现线程死锁的必须同时具备的4个条件:

    1:互斥条件.即至少存在一个资源,不能被多个线程同时共享.

    2:至少存在一个线程,他拥有一个资源,并等待获得另一个线程当前锁拥有的资源.

    3:线程拥有的资源不能被强制剥夺,只能由线程释放.

    4:线程对资源的请求形成了一个圆环.

    10.8 线程池

    因为创建和清除线程垃圾都会大量占用CPU等系统资源,所以可以使用线程池来解决资源浪费的问题.

    线程池的思想是:在系统中开辟一块区域,其中存放一些待命的线程,这个区域称为线程池,如果需要执行任务,则从线程池中一个待命的线程来执行指定的任务,等到任务结束可以再将所取的线程放回.这样就避免上面所说的问题.常用的线程池有 固定尺寸线程池和可变尺寸线程池,这种线程池中待命的数量是根据任务负载的需要动态变化的.

    public class FixText implements Runnable

    {

    public static void main(String[] args)

    {

    // 创建尺寸为2的固定线程池

    ExecutorService threadpool = Executors.newFixedThreadPool(2);

    // 创建3个任务对象

    FixText ft1 = new FixText("FT1");

    FixText ft2 = new FixText("FT2");

    FixText ft3 = new FixText("FT3");

    // 启动三个任务执行

    threadpool.execute(ft1);

    threadpool.execute(ft2);

    threadpool.execute(ft3);

    threadpool.shutdown();

    }

    private String name;

    public FixText(String name)

    {

    this.name = name;

    }

    public void run()

    {

    System.out.println(" --------" + this.name + "开始执行");

    for (int i = 0; i < 50; i++)

    {

    System.out.print("[" + this.name + "]");

    }

    System.out.println(" --------" + this.name + "执行结束");

    }}

  • 相关阅读:
    C#实现-浏览器UA解析获得手机、系统、浏览器等信息
    C#代码实现-冒泡排序
    C# DateTime 工具类
    net core 3.1 跨域 Cors 找不到 “Access-Control-Allow-Origin”
    C#/.Net开发入门篇(3)——console类的输入输出
    C#/.Net开发入门篇(2)——第一个控制台应用程序
    C#/.Net开发入门篇(1)——开发工具安装
    docker 学习笔记(2)--docker file命令
    docker 学习笔记(1)--常用命令
    导出大数据方法。批量导BOM
  • 原文地址:https://www.cnblogs.com/qingtianBKY/p/6039062.html
Copyright © 2011-2022 走看看