几个程序解惑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集合中的元素进行拷贝,只是拷贝了引用。否则的话,会有更多的问题。
相关文章推荐
- Java 程序中的多线程
- Java程序中的多线程
- 使用Java程序的泛型应该注意的几个地方
- JAVA面试题解惑系列(二)——到底创建了几个String对象?
- Java 程序中的多线程
- Java多线程的几个重要概念
- JAVA面试题解惑系列(十)――话说多线程
- Java 程序中的多线程
- JAVA面试题解惑系列(二)——到底创建了几个String对象?
- JAVA面试题解惑系列(二)——到底创建了几个String对象?
- 影响Java程序运行的几个问题
- 如何使用Java编写多线程程序
- JAVA写的多线程下载程序,并具有断点续传功能
- Java 程序中的多线程
- 多线程高性能 7x24小时 Java NewIO 程序 小结
- Java 程序中的多线程
- 一个使用多线程删除指定目录及子目录下所有指定文件的Java程序(源码)
- Java 程序中的多线程
- JAVA解惑---String创建了几个对象
- JAVA面试题解惑系列(二)——到底创建了几个String对象?