1. 利用类对象进行同步
当两个线程访问同一个类对象时,发生竞争。同步加锁的是对象,而不是代码。
package thrds;
public class FiveThread {
public static void main(String args[])
{
ThTst obj = new ThTst();
Thread t1 = new Thread(obj); // 两个线程用同一个对象,发生互斥(属于对象互斥)
Thread t2 = new Thread(obj);
t1.start();
t2.start();
}
}
class ThTst extends Thread {
public void run() {
tst();
}
synchronized void tst()
{
System.out.println(Thread.currentThread().getId() + " in");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getId() + " out");
}
}
输出结果:
15 in
15 out
14 in
14 out
如果将上述 main函数中改为:
Thread t1 = new Thread(new ThTst()); // 使用两个对象,不会发生竞争
Thread t2 = new Thread(new ThTst());
输出结果:
17 in
15 in
15 out
17 out
2. 使用类定义和 对象 进行同步(类.class)
即使两个线程分别访问不同的对象,也会发生竞争。加锁的是代码段。
因为一个类的类定义只有一个,因此,到加锁的地方,只能有一个线程进去执行。
注意:null不可用来作为同步对象。
package thrds;
public class SixThread {
public static void main(String args[])
{
Thread t1 = new Thread(new ThTst2());
Thread t2 = new Thread(new ThTst2());
t1.start();
t2.start();
}
}
class ThTst2 extends Thread {
private static Integer iObj = 9;
public void run() {
tst();
}
synchronized void tst()
{
synchronized (ThTst2.class) { //这里可用任何类类型,如 String.class, Integer.class 或使用 其他对象如iObj 也是一样的
System.out.println(Thread.currentThread().getId() + " in");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getId() + " out");
}
}
}
输出结果:
14 in
14 out
16 in
16 out
3. 2中使用对象同步,用来同步的对象,可由参数传入。这样,可提供更多的灵活性,程序员可以控制哪几个线程竞争同一个对象。(在设计时可参考)
package thrds;
import org.omg.CORBA.INV_OBJREF;
public class SevenThread {
public static void main(String args[])
{
ThTst3 tObj1 = new ThTst3();
ThTst3 tObj2 = new ThTst3();
String lock = new String("lock");
tObj1.setLock(lock);
tObj2.setLock(lock);
Thread t1 = new Thread(tObj1);
Thread t2 = new Thread(tObj2);
t1.start();
t2.start();
}
}
class ThTst3 extends Thread {
private String lock = null;
@Override
public void run() {
tst();
}
synchronized void tst()
{
synchronized (lock) { //同步对象由参数传入
System.out.println(Thread.currentThread().getId() + " in");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
System.out.println(Thread.currentThread().getId() + " out");
}
}
void setLock(String lock)
{
this.lock = lock;
}
}
输出结果:
15 in
15 out
16 in
16 out
synchronized关键字,多线程在同步时,需要看用来同步的对象(包括类定义)是不是唯一的。只有对象是唯一的时候,才会发生互斥。