几个程序解惑java多线程

来源:互联网 发布:visio网络拓扑图素材 编辑:程序博客网 时间:2024/06/06 06:47
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集合中的元素进行拷贝,只是拷贝了引用。否则的话,会有更多的问题。



0 0
原创粉丝点击