技术开发 频道

JAVA线程:如何解决资源共享冲突(上)

  【IT168技术】前文中我讲到了java里如何去创建一个线程的问题,代码里创建的线程都是独立的,也就是说创建的线程都不会相互的干扰,独立的进行属于自己的运算,更重要的是文章里创建的线程所使用的资源都是独占式的,不会有人跟它争,但是实际对线程的应用中,更多的也是更难的还是几个线程会抢夺同一个资源,比如火车的售票系统,碰到这样的问题就麻烦多了。

  相关阅读:JAVA线程:两种不同创建方式全面解析

  由于这个问题比较复杂我把线程的基础篇中篇分为两篇文章来发布,今天是前篇。回到主题吧,当N多的线程同时访问一个资源,并且N多的线程都有对这个资源修改和访问的能力,解决资源冲突的技术就太重要了,记得我在研究前端优化技术的时候,脑海里浮现最多的名词就是高并发,而对于网站在高并发下又能保证数据的准确性的问题,在我知道java线程调度机制是随机切换时间片的时候,我就感到这个问题比想象中要复杂的多。

  为了便于阐述我要讲的主题,我想要写一个监控程序(Watcher),这个监控程序可以随时检查我们调用的资源的内容比如数字,代码如下:

package cn.com.sxia;

public class AlwaysEven {

private int i;
public void next(){
i++;
i++;
}
public int getValue(){
return i;
}
public static void main(String[] args) {
final AlwaysEven ae = new AlwaysEven();
new Thread("Wacther"){
public void run(){
while(true){
int val = ae.getValue();
if (val % 2 == 0){
System.out.println(val);
System.exit(0);
}
}
}
}.start();
while(true)
{
ae.next();
}
}

}

  程序注解如下:

  AlwaysEven类里有一个属性i,next方法每执行一次i的值会自动加2,getValue返回i的数值。在main函数里我们构建了一个AlwaysEven对象ae,注意这个变量前一定要用final,否则在监控线程里是不能访问到这个变量,最后我们写了一个死循环:调用next方法。

  当我们多次执行这个main函数,发现打印出来的结果都会不一样。这个现象道出了运用线程所会遇到的一个基本问题:我们永远都不知道线程何时会运行。这个感觉就像我们创造了一支笔,想用它写字,写着写着,在没有任何征兆的情况下笔不见了,这个实在是很郁闷,但这种情况就是我们在写并发程序经常会遇到的问题。

  上面的例子也表现了不同线程共同使用一个资源的现象,监控线程监视ae对象里i属性的数值变化,在主线程main里面又不断调用next方法增加i的数值。这就是在争抢同一个资源的实例。

  为了更好阐述我后面要阐述的内容,这里我要补充一下在上篇里漏掉的一部分线程的知识:后台线程(daemon)。后台线程(daemon)是指在程序运行的时候在后台提供一种通用服务的线程,并且这种线程不是属于程序里不可或缺的部分。所以,当所有的非后台线程结束时,程序也就终止了,反过来说只要有任何非后台线程还在运行,程序就不会终止。大家看下面的代码:

package cn.com.sxia;

public class SimpleDaemon extends Thread {

public SimpleDaemon(){
setDaemon(true);
start();
}
public void run(){
while(true){
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this);
}
}
public static void main(String[] args) {
for (int i = 0;i < 10;i++){
new SimpleDaemon();
}
}

}
0
相关文章