Java中的线程安全问题
在编程实际应用中常常需要多个线程并发地工作以充分提高计算机的系统资源利用效率,从而大大提高系统的工作处理效率。但与此同时伴随的会产生线程安全问题。
由于多个线程不断地争夺共享数据,因此会产生多个线程同时进入共享数据并进行更改或其他相关的操作,于是导致数据被相互竞争的线程进行不可预计的操作,为解决这个问题,java提供了同步机制决绝线程安全问题。
下面给一个实例——生产者消费者问题:生产者消费者共用一个产品缓冲池,生产者消费者分别互斥地使用缓冲池。生产者只有在缓冲池有空闲区域时可以向产品缓冲区投入生产的产品。消费者只有在产品缓冲池中产品不为空的情况下才可以从缓冲池中取商品。
根据以上场景建立模型,这里仅演示producer与consumer互斥地使用commodity pool的代码,方便读者理解java synchronized在解决线程安全问题时的作用。
Job类定义produce(),consume()方法,分别代表生产动作与消费动作
package pers.me.timlong.Thread;
/**
* 生产者与消费者问题,线程间通信
* @author lenovo
*
*/
public class Job {
private boolean flag = true;
//工厂方法
public synchronized void produce() {
while(!flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int i = 0;
for(i = 0; i < 10; i ++) {
System.out.println("product: " + i);
}
flag = false;
this.notify(); // 用来唤醒consumer wait()
}
public synchronized void consume() {
while(flag) {
try {
this.wait(); //释放
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int i = 0;
for(i = 0; i < 10; i++) {
System.out.println("consumer: " + i);
}
flag = true;
this.notify(); //唤醒factory线程wait()
}
}
调用类:
package pers.me.timlong.Thread;
public class ThreadCommunication {
public static void main(String[] args) {
final Job myjob = new Job();
new Thread(new Runnable() {
@Override
public void run() {
int i = 0;
for(i = 0; i < 50; i++) {
myjob.produce();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
int i = 0;
for(i = 0; i < 50; i++) {
myjob.consume();
}
}
}).start();
}
}
运行效果:
结果显示,在多线程下,product方法与consumer方法都能够各自连续完成而后再转去实现其他放啊发,关键在于在方法使用关键词使用synchronized修饰,实现各方法的互斥执行,保证了线程安全。
读者可以尝试将synchronized关键词删去运行检验运行效果,由于线程间不断竞争资源获得运行,将会出线比较混乱的执行结果。
望每天进步一点,