问题描述
我现在有一个这样的资源类,可能的方法如下所示class A {List test;set(); // 初始化test,并赋值reset(); // 请空test,并对test重新赋值get(int index); // 取test中的某个值}一般情况下test初始化后有多个线程会调用get()方法取值,为了保证效率也不需要同步get()方法,但一定概率下会有其他线程对test调用reset()方法,我的需求是:当有线程调用reset()方法时(同一时刻只有一个线程调用reset()),其他线程再调用get()时,必须等待reset()结束后,方可继续。主要是避免读取错误!我想请问一下大家谁有比较好的解决方案? 问题补充:由于我的系统在绝大多数情况下都是在(多个线程)调用get()方法,如果对get()同步,效率将大大降低,可能不符合要求!非常感谢您的回答,以下是我在您提供的方案上修改后做的测试代码!package test;import java.util.ArrayList;import java.util.List;import java.util.Random;public class TestSync {private List<String> lists = new ArrayList<String>();public TestSync() {lists.add("张三");lists.add("李四");lists.add("张三");lists.add("李四");lists.add("张三");lists.add("李四");lists.add("张三");lists.add("李四");lists.add("张三");lists.add("李四");lists.add("张三");lists.add("李四");lists.add("张三");lists.add("李四");}public void reset() {synchronized (this) {System.out.println(Thread.currentThread().getName() + "正在执行reset()");lists.clear();try {Thread.sleep(5000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}lists.add("张三");lists.add("李四");lists.add("张三");lists.add("李四");lists.add("张三");lists.add("李四");lists.add("张三");lists.add("李四");lists.add("张三");lists.add("李四");lists.add("张三");lists.add("李四");lists.add("张三");lists.add("李四");lists.add("张三");lists.add("李四");lists.add("张三");lists.add("李四");System.out.println(Thread.currentThread().getName() + "reset()执行完毕");}}public synchronized String get(int i) {System.out.println(Thread.currentThread().getName() + "执行get(int i)");try {Thread.sleep(2000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}return lists.get(i);}}class TestThread extends Thread {private TestSync a = null;public TestThread(TestSync a) {this.a = a;}@Overridepublic void run() {// TODO Auto-generated method stubint loop = 20;while (loop > 0) {loop--;a.get((new Random()).nextInt(6));if ((int) (Math.random() * 10) == 1) {a.reset();} else {a.get((new Random()).nextInt(14));}}}}
解决方案
为什么呢?下面是我机器上的执行结果Thread-0执行get(int i)Thread-0执行get(int i)Thread-1执行get(int i)Thread-0正在执行reset()Thread-0reset()执行完毕Thread-1执行get(int i)Thread-1执行get(int i)Thread-1执行get(int i)Thread-1执行get(int i)Thread-1执行get(int i)Thread-1正在执行reset()Thread-1reset()执行完毕Thread-1执行get(int i)Thread-0执行get(int i)Thread-0执行get(int i)Thread-0执行get(int i)Thread-0执行get(int i)Thread-0执行get(int i)Thread-0执行get(int i)Thread-0执行get(int i)Thread-0执行get(int i)Thread-0执行get(int i)Thread-0执行get(int i)Thread-0执行get(int i)Thread-0执行get(int i)Thread-0执行get(int i)Thread-0执行get(int i)Thread-0执行get(int i)Thread-0执行get(int i)Thread-0执行get(int i)Thread-1执行get(int i)Thread-1执行get(int i)Thread-1执行get(int i)Thread-1正在执行reset()Thread-1reset()执行完毕Thread-1执行get(int i)Thread-1执行get(int i)Thread-1执行get(int i)Thread-1执行get(int i)Thread-1执行get(int i)Thread-1执行get(int i)Thread-1执行get(int i)Thread-1执行get(int i)分析一下上面的结果:Thread-1正在执行reset()Thread-1reset()执行完毕之间没有任何的get(int i)操作,可是在reset()方法中,线程要sleep(5000),这么长的时间,其他的线程都没有执行get(int i)操作,这不是你的要求吗?你也可以把sleep的时间设置成更长的时间,在reset方法执行完之前,其他的线程是不能get方法的
解决方案二:
只要简单的在reset()方法中加入以下代码:reset(){synchronized(this){ // 这里添加功能 // 请空test,并对test重新赋值 }}下面的代码为验证想法的一个代码import java.util.ArrayList;import java.util.List;class A {private List<String> lists = new ArrayList<String>();public A() {lists.add("张三");lists.add("李四");}public void reset() {synchronized (this) {System.out.println(Thread.currentThread().getName() + "正在执行reset()");try {Thread.sleep(5000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}lists.clear();lists.add("张三");lists.add("李四");System.out.println(Thread.currentThread().getName() + "reset()执行完毕");}}public synchronized String get(int i) {System.out.println(Thread.currentThread().getName() + "执行get(int i)");return lists.get(i);}}class TestThread extends Thread {private A a = null;public TestThread(A a) {this.a = a;}@Overridepublic void run() {// TODO Auto-generated method stubint loop = 20;while (loop > 0) {loop--;if ((int) (Math.random() * 10) == 1) {a.reset();} else {a.get(1);}}}}public class T1 {/** * @param args */public static void main(String[] args) {// TODO Auto-generated method stubA a = new A();TestThread t1 = new TestThread(a);TestThread t2 = new TestThread(a);TestThread t3 = new TestThread(a);TestThread t4 = new TestThread(a);t1.start();t2.start();// t3.start();// t4.start();}}
解决方案三:
import java.util.List;class Test1 {List test; boolean isLocked =false;void set() {}synchronized void reset() {isLocked = true;System.out.println("start this is reset");try {Thread.sleep(300);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}/*****/System.out.println("end this is reset");isLocked = false;}int get(int index) { //这里等待reset()执行完。while (isLocked) {System.out.println("00000000000");}return index;}public static void main(String[] args) {final Test1 t = new Test1();new Thread(new Runnable(){public void run(){t.reset();}}).start();new Thread(new Runnable(){public void run(){System.out.println("ssssssssss:"+t.get(0));}}).start();}}