您的位置:首页 > 编程语言 > Java开发

几个程序解惑java多线程

2015-01-24 17:22 253 查看
public class Test implements Runnable
{
Thrd thd;
Test2(Thrd thd){
this.thd = thd;
}
public void run(){
while(true){
int v = thd.getNext();
System.out.println(Thread.currentThread().getName()+" : "+v);
try{Thread.sleep(1000);}catch(Exception e){}
}
}
public static void main(String args[]){
new Thread(new Test(new Thrd())).start();
new Thread(new Test(new Thrd())).start();
}
}
class Thrd
{
private int value = 0;
public synchronized int getNext(){
return value++;
}
}

这里在类Thrd中getNext方法使用了synchronized,也就是说这是一个同步方法,那么Test的main方法中,返回的value是不是会不同呢。运行程序(这里用了死循环)发现两个线程之间并没有同步,为什么呢?

原因很简单对于每个线程,我们传递了不同的Thrd类的实例,每个实例都有自己的getNext方法,二者之间是不同的。

现在我们把Thrd类做如下修改:

class Thrd
{
private static int value = 0;
public synchronized static int getNext(){
return value++;
}
}


运行程序,发现现在value在两个线程之间实现了同步。而原因就是现在getNext方法成为了类方法,两个线程访问的是同一个方法实例,所以可以同步。

现在给出一个复杂一点的程序(论坛上找的),我们可以按照上面的思路分析了。

import java.util.*;
public class Test extends Thread{
private String st;
private static List<String> list = new ArrayList<String>();
public Test(int i) {
st = "str" + i;
}
public static void main(String[] args) throws Exception {
String[] arr = new String[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = "str" + i;
list.add(arr[i]);
}
for (int i = 0; i < arr.length; i++) {
Test test = new Test(i);
test.start();
}
while(true){
if (list.isEmpty()) {
break;
}
sleep(500);
}
System.out.println("finished");
}
public void run() {
removeStr(st);
System.out.println(st);
}
public synchronized static void removeStr(String str) {
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String strTemp = it.next();
if (strTemp.equals(str)) {
it.remove();
break;
}
}
}
public synchronized static boolean isEmpty() {
return list.isEmpty();
}
}
现在程序变得复杂了,而且由于包含了对线程非安全的list的操作,难度增大了。

这个程序是正确的,假如现在把方法removeStr和isEmpty前面的static去掉(如前所述,这时方法变为每个程私有的),程序可能会出现3中运行结果。下面我们一一分析。

首先需要说明的是,Test test = new Test(i); test.start();从这两句可知,第i个线程st=“stri”;线程start之后,每个线程从list中寻找元素跟stri相同的元素,并将其删除。其中,list是static的,每个线程共享。

1.运行正常结束。

这取决于一种特定的线程执行顺序,就是每个线程在对list进行操作的时候没有形成竞争条件,最后恰好删除list中所有元素,main函数中list.isEmpty()为真,循环结束,main也随之结束。

2.死循环。

这个是因为--size(通过remove源码可以知道)时,被另外一个线程抢占并同样进行了--size的操作。(考虑每一个线程的工作栈,事先会对size进行拷贝,size被另外一个线程改变后,上一个线程看到的还是旧的size值)

3.抛出ConcurrentModificationException。

原因是其中一个线程在it.next()与it.remove()之间被另外一个线程抢占并执行进行了删除操作。

而且还可以看到,每个线程的工作栈中并没有对list集合中的元素进行拷贝,只是拷贝了引用。否则的话,会有更多的问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: