多线程的交互

当多个线程同时共享访问同一数据时,每个线程都尝试操作该数据,从而导致改数据被破坏,这种现象称为争用条件。

同步的实现:wait(),notify(),notifyAll()   

当一个线程要访问共享资源,首先要拿到锁后进入临界区,如果发现某些条件不符合,调用wait方法释放锁资源,线程进入锁对象上的Wait Set,

拿到锁的当前运行进程执行完时调用notify()会唤醒锁资源所持有的等待区域中的一条线程(随机),使该线程有机会竞争CPU资源;

调用notifyAll()会唤醒锁资源所持有的等待区域中的所有线程,使这些线程有机会竞争CPU资源;

EnergySystem:

/**
 * 宇宙的能量系统
 * 遵循能量守恒定律:
 * 能量不会凭空创生或消失,只会从一处转移到另一处
 */
public class EnergySystem {

    //能量盒子,能量存贮的地方
     private final double[] energyBoxes;
     private final Object lockObj = new Object();

     /**
      *
      * @param n    能量盒子的数量
      * @param initialEnergy 每个能量盒子初始含有的能量值
      */
     public EnergySystem(int n, double initialEnergy){
         energyBoxes = new double[n];
         for (int i = 0; i < energyBoxes.length; i++)
             energyBoxes[i] = initialEnergy;
     }

     /**
      * 能量的转移,从一个盒子到另一个盒子
      * @param from 能量源
      * @param to     能量终点
      * @param amount 能量值
      */
     public void transfer(int from, int to, double amount){
         synchronized(lockObj){
//             if (energyBoxes[from] < amount)
//                 return;
            //while循环,保证条件不满足时任务都会被条件阻挡
             //而不是继续竞争CPU资源
             while (energyBoxes[from] < amount){
                 try {
                    //条件不满足, 将当前线程放入Wait Set
                    lockObj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
             }
             System.out.println(Thread.currentThread().getName());
             energyBoxes[from] -= amount;
             //System.out.printf("从%d转移%10.2f单位能量到%d", from, amount, to);
             energyBoxes[to] += amount;
            // System.out.printf("      能量总和:%10.2f%n", getTotalEnergies());
            //唤醒所有在lockObj对象上等待的线程
             lockObj.notifyAll();
         }
     }
      // 获取能量世界的能量总和
     public double getTotalEnergies(){
         double sum = 0;
         for (double amount : energyBoxes)
             sum += amount;
         return sum;
     }
      // 返回能量盒子的长度
     public  int getBoxAmount(){
         return energyBoxes.length;
     }
}

EnergyTransferTask:

public class EnergyTransferTask implements Runnable{

    //共享的能量世界
    private EnergySystem energySystem;
    //能量转移的源能量盒子下标
    private int fromBox;
    //单次能量转移最大单元
    private double maxAmount;
    //最大休眠时间(毫秒)
    private int DELAY = 10;

    public EnergyTransferTask(EnergySystem energySystem, int from, double max){
        this.energySystem = energySystem;
        this.fromBox = from;
        this.maxAmount = max;
    }

    public void run() {
        try{
            while (true){
                int toBox = (int) (energySystem.getBoxAmount()* Math.random());
                double amount = maxAmount * Math.random();
                energySystem.transfer(fromBox, toBox, amount);
                Thread.sleep((int) (DELAY * Math.random()));
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

public class EnergySystemTest {

    //将要构建的能量世界中能量盒子数量
    public static final int BOX_AMOUNT = 100;
    //每个盒子初始能量
    public static final double INITIAL_ENERGY = 1000;

    public static void main(String[] args){
        EnergySystem eng = new EnergySystem(BOX_AMOUNT, INITIAL_ENERGY);
        for (int i = 0; i < BOX_AMOUNT; i++){
            EnergyTransferTask task = new EnergyTransferTask(eng, i, INITIAL_ENERGY);
            Thread t = new Thread(task,"TransferThread_"+i);
            t.start();
            System.out.println(t.activeCount());
        }
    }

}

EnergySystemTest

输出结果:

在for循环中from是递加的,但结果并不是从0,1,2.......按顺序转移?

虽然进程按顺序创造task但start方法不会等到run方法执行完就会继续执行下面的代码,所以导致创建了很多线程但他们随机执行run方法。

时间: 2024-11-06 05:46:36

多线程的交互的相关文章

生产者消费者模型实现多线程异步交互

[Python之旅]第六篇(五):生产者消费者模型实现多线程异步交互 消息队列 生产者消费者模型 多线程异步交互 摘要:  虽然标题是"生产者消费者模型实现多线程异步交互",但这里要说的应该还包括Python的消息队列,因为这里多线程异步交互是通过Python的消息队列来实现的,因此主要内容如下: 1 2 3 4 1.生产者消费者模型:厨师做包子与顾客吃包子 2.Python的消息队列 3.利用... 虽然标题是"生产者消费者模型实现多线程异步交互",但这里要说的应

java之 ------ 多线程(交互线程)

1.运行结果不惟一,取决于线程调度 2.线程执行被打断时出现错误 3.线程互斥和临界区管理 1)操作系统对共享一个变量的若干线程进入各自临界区有以下3个调度原则: 2)一次至多一个线程能够在它的临界区内. 3)不能让一个线程无限地留在它的临界区内. 4)不能强迫一个线程无限地等待进入它的临界区.特别地,进入临界区的任一线程不能妨碍正等待进入的其他线程的进展. 4.同步语句   synchronized (对象) 同步方法  synchronized  方法声明   方法声明synchronize

python多线程--管道交互

1.管道使用 ''' 管道Pipe ''' from multiprocessing import Process,Pipe def f(conn): conn.send('child message') conn.close() if __name__=='__main__': parent_conn,child_conn=Pipe() p=Process(target=f,args=(child_conn,)) p.start() print(parent_conn.recv()) p.jo

多线程概念

一个进程是由一个或者N个线程组成的! 线程:cpu调度和分配的基本单位!电脑中真正执行的是线程! 在同一个时间点,我们的电脑只能运行一个线程 多线程: 如果在一个进程中,同时运行多个线程,来完成不同的工作,我们称之为多线程! CUP不能同时运行多个线程! 一个CPU在同一个时间点,只能运行一个线程,单线程运行的速度太快,我们肉眼无法分辨,所以我们认为是多线程! 生活中进入地铁站的例子: 场景1:现在地铁站有1个进站口,同时来了5个人! 需要排队进站! 场景2:现在地铁站有5个进站口,同时来了5个

多线程实践——概述与概念

 C#支持通过多线程并行地执行代码,一个线程有它独立的执行路径,能够与其它的线程同时地运行.一个C#程序开始于一个单线程,这个单线程是被CLR和操作系统(也称为“主线程”)自动创建的,并具有多线程创建额外的线程. 一个简单示例如下: using System; using System.Threading; class ThreadDemo { static void Main() { Thread t = new Thread (WriteY); t.Start(); while (true)

进程、线程和多线程的概念

1. 什么是进程 当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源,而一个进程又是由多个线程所组成的. 2. 什么是线程 线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针.程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数. 3. 什么是多线程 多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务. 4. 多线程的好处 可以提高CPU

C#中的多线程-入门

概述与概念C#支持通过多线程并行地执行代码,一个线程有它独立的执行路径,能够与其它的线程同时地运行.一个C#程序开始于一个单线程,这个单线程是被CLR和操作系统(也称为“主线程”)自动创建的,并具有多线程创建额外的线程.这里的一个简单的例子及其输出: 除非被指定,否则所有的例子都假定以下命名空间被引用了: using System; using System.Threading; class ThreadTest {static void Main() {Thread t = new Threa

java多线程并发概览

一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程.比如在Windows系统中,一个运行的exe就是一个进程. 线程是指进程中的一个执行流程,一个进程中可以运行多个线程.比如java.exe进程中可以运行很多线程.线程总是属于某个进程,进程中的多个线程共享进程的内存. "同时"执行是人的感觉,在线程之间实际上轮换执行. 二.Java中的线程 在J

java之 ------ 多线程(从基础到加强)

首先了解线程的一些基本知识: 1.线程的定义: 是操作系统进程中能够独立执行的实体(控制流),是处理器调度和分派的基本单位. 2.线程的属性: 并发性.共享性.动态性和结构性 3.线程的状态 然后就是java与线程的调度: 1.主要是通过实现Runnable接口和继承Thread类来实现线程的调度和操作 a.Runnable接口(里面就一个run方法,只要通过重写run方法就可以实现自己想要的线程功能) public interface Runnable { public abstract vo