多线程信息共享
- 线程类
– 通过继承Thread或实现Runnable接口
– 通过start方法,调用run方法,run方法工作
– 线程run结束后,线程退出 - 粗粒度:子线程与子线程之间、main线程之间缺乏交流
- 细粒度:线程之间有信息交流通讯
– 通过共享变量达到信息共享
– JDK原生库暂不支持发送消息(类似MPI并行库直接发送消息)
MPI是一个信息传递应用程序接口,包括协议和语义说明。MPI的目标是高性能,大规模性,和可移植性。MPI在今天仍为高性能计算的主要模型 - 通过共享变量在多个线程中共享消息
– static变量
– 同一个Runnable类的成员变量
/**
* @ClassName:ThreadDemo0
* @Description:
* @author: Torey
*/
public class ThreadDemo0 {
public static void main(String[] args){
for (int i = 0; i < 4; i++) {
new TestThread0().start();
}
}
}
class TestThread0 extends Thread{
//每个线程卖2张,4个线程卖8张
private int tickets=2;
//所有线程卖2张,4个线程卖2张
//private static int tickets=2;
@Override
public void run() {
while (true){
if (tickets>0) {
tickets--;
System.out.println(Thread.currentThread().getName() + " tickets=" + tickets);
}else {break;}
}
}
}
/**
* @ClassName:ThreadDemo1
* @Description:
* @author: Torey
*/
public class ThreadDemo1 {
public static void main(String[] args){
TestDemo1 testDemo1=new TestDemo1();
//两个线程共享一个对象
new Thread(testDemo1).start();
new Thread(testDemo1).start();
}
}
class TestDemo1 implements Runnable{
private volatile static int tickets=4;
public void run() {
while (true) {
if (tickets>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
tickets--;
System.out.println(Thread.currentThread().getName()
+" :"+tickets);
}else {
break;
}
}
}
}
多线程共享问题
- 多线程信息共享问题
– 工作缓存副本
– 关键步骤缺乏加锁限制 - i++,并非原子性操作
– 读取主存i(正本)到工作缓存(副本)中
– 每个CPU执行(副本)i+1操作
– CPU将结果写入到缓存(副本)中
– 数据从工作缓存(副本)刷到主存(正本)中
工作缓存发(副本):是每个线程独有的内存空间 - 变量副本问题的解决方法
– 采用volatile关键字修饰变量
– 保证不同线程对共享变量操作时的可见性
volatile关键字代码示例
如下:不加volatile的变量,当主线程将flag设置为false后,子线程不能及时的读取到,导致while一直执行
加volatile的变量,当主线程将flag设置为false后,子线程可以及时的读取到,while循环跳出
源码如下:
/**
* @ClassName:ThreadDemo2
* @Description:volatile变量的使用
* @author: Torey
*/
public class ThreadDemo2 {
public static void main(String[] args) throws InterruptedException {
TestThread2 t = new TestThread2();
t.start();
Thread.sleep(2000);
t.flag=false;
System.out.println("main thread is exiting");}}
class TestThread2 extends Thread{
// boolean flag=true;//子线程不会停止,while里用的是工作缓存中的flag值,值是true,而主存里flag值为false,主存里的不能及时刷新到工作缓存中
volatile boolean flag=true;//用volatile修饰的变量可以及时在各线程里面通知
@Override
public void run() {
int i=0;
while (flag){i++;}
System.out.println("test thread is exiting");
}
}