概念:
线程间的通信有两种情况: 1、一个进程中的线程与另外一个进程中的线程通信,由于两个线程只能访问自己所属进程的地址空间和资源,故等同于进程间的通信。 2、同一个进程中的两个线程进行通信。
线程间的通信的主要目的是用于线程同步。
线程安全:
所在的进程中有多个线程在同时运行,而这些线程可能会同时某一段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。线程安全就是说多线程访问同一段代码不会产生不确定的结果。编写线程安全的代码依靠线程同步。
线程间的同步:
如果变量只读时,多个线程同时读取该变量不会有一致性问题,但是,当一个线程可以修改的变量,其他线程也可以读取或者修改的时候,我们就需要对这些线程进行同步,确保它们在访问变量的存储内容时不会访问到无效的值。
互斥锁:
互斥量本质上说是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量。对互斥量进行枷锁以后,其他视图再次对互斥量加锁的线程都会被阻塞直到当前线程释放该互斥锁。如果释放互斥量时有一个以上的线程阻塞,那么所有该锁上的阻塞线程都会变成可运行状态,第一个变成运行状态的线程可以对互斥量加锁,其他线程就会看到互斥量依然是锁着,只能再次阻塞等待它重新变成可用,这样,一次只有一个线程可以向前执行。
互斥量的死锁:
一个线程需要访问两个或者更多不同的共享资源,而每个资源又有不同的互斥量管理。当超过一个线程加锁同一组互斥量时,就可能发生死锁。死锁就是指多个线程/进程因竞争资源而造成的一种僵局(相互等待),若无外力作用,这些进程都将无法向前推进。
互斥与同步的区别:
互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。
同步:主要是流程上的概念,是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。
相关代码:
1.
ackage com.线程特性;
public class BaoZi {
String name;
boolean flag;
}
2.
package com.线程特性;
import javafx.scene.chart.ScatterChart;
public class ChiHuo extends Thread{
BaoZi baoZi;
public ChiHuo(String threadName,BaoZi bz){
super(threadName);
this.baoZi=bz;
}
/*吃货线程的功能
如果包子不在 线程进入等待状态
如果包子在 线程开始吃包子 吃完后更改包子的状态变为不存在 唤醒早餐店线程开始制作包子
* */
public void run(){
String threadName = Thread.currentThread().getName();
for (int i=0;i<10;i++){
synchronized (baoZi){
if (baoZi.flag){
System.out.println(threadName+"正在吃"+baoZi.name);
baoZi.flag= false;//更改包子状态
baoZi.notify();//唤醒同一资源下的其他线程
}else {
try {
baoZi.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
}
3.
package com.线程特性;
public class ZaoCanDian extends Thread{
BaoZi baoZi;
//定义构造方法
public ZaoCanDian(String threadName,BaoZi bz ){
super(threadName);
this.baoZi=bz;
}
/*
* 早餐店线程功能
* 如果包子存在 线程进入等待状态
* 如果包子不存在 线程开始制作包子 制作完毕更改包子状态为存在 唤醒吃货线程包子
* */
public void run(){
//获取线程名字
String threadName = Thread.currentThread().getName();
for (int i = 0;i<10;i++){
synchronized (baoZi){
if (baoZi.flag){
try{
baoZi.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{//包子不存在
System.out.println(threadName+"制作"+baoZi.name);//制造包子
baoZi.flag=true;//更改包子状态
baoZi.notify();//唤醒同一资源下的其他线程
}
}
}
}
}
4.
package com.线程特性;
public class ThreadTest01 {
public static void main(String[] args) {
BaoZi bz = new BaoZi();
bz.name="韭菜鸡蛋";
bz.flag=false;
ChiHuo ch = new ChiHuo("猪八戒",bz);
ZaoCanDian zcd = new ZaoCanDian("春光早餐",bz);
ch.start();
zcd.start();
}
}