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