28、Java入门—多线程之线程交互

线程常用方法


      1.获取线程名称:getName();


      2.取得当前线程对象:currentThread();


      3.判断是否启动:isAlive();


      4.强行运行:join();


      5.线程休眠:sleep();


      6.线程礼让:yield();

格式输出方式
  %d表示输出一个整数值
  %10.2f表示一个浮点值 10表示小数点前是10位,2表示小数点后为2位
  %n等于/n,即空格换行


争用条件(Race Condition):当多个线程同时共享访问同一数据(内存区域)时,每个线程都尝试操作该数据,从而导致数据被破坏(corrupted),这种现象称为争用条件。


Java线程——线程交互——争用条件
  1、当多个线程同时共享访问同一数据(内存区域)时,每个线程都尝试操作该数据,从而导致数据被破坏(corrupted),这种现象称为争用条件
  2、原因是,每个线程在操作数据时,会先将数据初值读【取到自己获得的内存中】,然后在内存中进行运算后,重新赋值到数据。 
  3、争用条件:线程1在还【未重新将值赋回去时】,线程1阻塞,线程2开始访问该数据,然后进行了修改,之后被阻塞的线程1再获得资源,而将之前计算的值覆盖掉线程2所修改的值,就出现了数据丢失情况


一、互斥
1、同一时间,只能有一个线程访问数据
二、同步
1、是一种通信机制,一个线程操作完成后,以某种方式通知其他线程
三、实现方法
1、【互斥】构建锁对象(Object objLock),通过synchronized(lockObj){ 互斥的代码块 }
2、加锁操作会开销系统资源,降低效率。
3、在某线程的条件不满足任务时,使用lockObj.wait()对线程进行阻挡,防止其继续竞争CPU资源,滞留在wait set中,等待唤醒,【唤醒后继续完成业务】
4、【同步】在某一代码正确执行完业务后,通过lockObj.notifyAll()唤醒所有在lockObj对象等待的线程

线程的交互:互斥与同步
互斥:在同一时间只能有一条线程对关键数据或临界区进行操作
同步:线程之间的一种通信机制 
一条线程做了一件事情,然后用某种方式去告诉其它线程:"我做完了"
synchronized关键字实现互斥行为,既可以出现在方法体之上也可以出现在方法体内,以一种块的形式出现。
然后通过lockObject的wait方法(注意:wait的线程被存放在wait set 中)和notifyAll方法实现同步。
步骤:
1.互斥:同一时间,只能有一个线程访问数据
2.同步:通信机制;一个线程完成,以某种方式通知其他线程
3.锁的概念:private final Object lockObj = new Object();
4.互斥实现方式:synchronized关键字
synchronized(lockObj){---执行代码----}加锁操作
lockObj.wait();线程等待状态,以避免线程持续申请锁,不去竞争cpu资源
lockObj.notifyAll();唤醒所有lockObj对象上等待的线程


如何进行互斥?
增加锁对象——lockObj
synchronized(lockObj){


关键代码


}


如何实现同步?
锁对象.wait();
锁对象.notify();
锁对象.notifyAll();
这3个方法都是属于Object对象
是该对象的成员函数,而非Thread,
构成了同步。




注意:


wait()和notifyall()不是在同一个线程的同一次操作中进行的。
同步是两个线程之间的交互,一个发出操作,一个响应操作。

同步的实现:wait()/notify()/notifyAll(),三个方法都是属于java中Object对象,而非Thread对象,即都是Object类的成员函数

wait()可以让线程进入等待状态。
notify()可以唤醒等待的线程,但只能随机唤醒一个;
notifyAll()可以唤醒所有等待的线程,同时去争抢资源的控制,抢到者去执行,其他则继续等待。

线程互斥的实现:synchronized(instrinsic lock)
相当于给代码加上一把锁,使得其他线程不能够进入这个关键区域访问关键资源

调用wait()方法使线程进入等待状态,以及调用notifyAll()方法使所有的线程被唤醒不是在同一个线程的同一次操作中执行的!!!!!!
所谓同步一定是两个线程之间的一个交互的操作,一个发出消息而另一个响应这种消息。
当最后使用notifyAll()唤醒了所有的等待线程之后,所有的线程都将有公平的机会去竞争我们的CPU资源

Wait Set概念(线程休息室)


共享资源(Critical Section)---- 临界区
[当访问共享资源时,先要获得锁,然后进行操作,判断是否符合要求,不满足则调用锁的wait()方法,然后进入锁的Wait Set]

/**
 * 宇宙的能量系统
 * 遵循能量守恒定律:
 * 能量不会凭空创生或消失,只会从一处转移到另一处
 */
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.print(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;
}
 
}

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();
    }
    }


}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值