第一遍粗略看三各类,声明了什么变量 , 和写了什么方法名
首先新建一个类叫树类吧 :下面的方法用synchronized修饰可以一会再看
public class Tree {
int value;
public synchronized void Add(){ //不是从方法内部声明的变量才需要锁
value +=1;
//只锁以给Add()方法加锁,而不给线程类的run方法加锁,是因为:在线程run方法中加,锁不住value变量
}
}
然后新建一个线程类:
在这我们在这写了一个线程调用时的run方法,和一个构造方法(可有可无,但是我这用到了)。
import javax.naming.Name;
public class ThreadTest extends Thread {
private String name;
private Tree tree ;
ThreadTest(String name,Tree tree) {
this.name = name;
this.tree = tree;
}
// synchronized 只要锁住了Add方法就 不用锁run ,这样的好处是由于此处没加锁_节省效率,<<只锁调用资源的方法就行>>
public void run() {
for (int i = 0; i < 300; ++i){
System.out.println("====" + name);//输出调用的过程
tree.Add();//通过锁住Add()方法,来实现锁住value 而不能直接调用 tree.value += 1
//这里不可以用 tree.value +=1 , 这样是锁不住的,只能锁住tree但是锁不住 tree.value
}
}
}
下面是对我们写好的类进行测试,新建了两个线程 t1和 t2 调用线程 。try/catch语句是为了帮助线程先完成再看结果,
import org.omg.Messaging.SyncScopeHelper;
public class TestThread {
public static void main(String[] args) {
Tree tree = new Tree();
tree.value = 0;
ThreadTest t1 = new ThreadTest("调用线程1",tree);
ThreadTest t2 = new ThreadTest("调用线程2",tree);
t1.start();
t2.start();
try {
t1.join();//这样可以先加入线程再输出值
t2.join();
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(tree.value);//发现变成了我们所期望的600
}
}
下面进行第二遍梳理:
如果你觉得有疑问可以试一下将如下代码段改变,然后多运行几次,你会发现结果是不稳定的,这就说明锁没有把value锁住。
因为 synchronized 只是锁住了 tree 并没锁住 tree.value。 剩下的看一下注释吧
public void run() {
for (int i = 0; i < 300; ++i){
System.out.println("====" + name);//输出调用的过程
tree.Add();//通过锁住Add()方法,来实现锁住value 而不能直接调用 tree.value += 1
//这里不可以用 tree.value +=1 , 这样是锁不住的,只能锁住tree但是锁不住 tree.value
}
}
变为:下面是不能锁住的代码,因为 synchronized 只是锁住tree这个对象
public synchronized void run() {
for (int i = 0; i < 300; ++i){
System.out.println("====" + name);//输出调用的过程
tree.value +=1
}
}