synchronized使用起来非常简单,有三种使用模式:
1. 作为修饰符加在方法声明上,synchronized修饰非静态方法时表示
锁住了调用该方法的堆对象,修饰静态方法时表示
锁住了这个类在方法区中的类对象(记住JAVA中everything is object)。
2.可以用synchronized直接构建代码块。
3.在使用Object.wait()使当前线程进入该Object的阻塞队列时,以及用Object.notify()或Object.notifyAll()唤醒该Object的阻塞队列中一个或所有线程时,必须在外层使用synchronized (Object),这是JAVA中线程同步的最常见做法。之所以在这里要强制使用synchronized代码块,是因为在JAVA语义中,
wait有出让Object锁的语义,要想出让锁,前提是要先获得锁,所以要先用synchronized获得锁之后才能调用wait,notify原因类似,另外,我们知道操作系统信号量的增减都是原子性的,而Object.wait()和notify()不具有原子性语义,所以必须用synchronized保证线程安全。
另外,在使用synchronized时有三个原则:
a)
sychronized的对象最好选择引用不会变化的对象(例如被标记为final,或初始化后永远不会变),原因显而易见的,虽然synchronized是在对象上加锁,但是它首先要通过引用来定位对象,如果引用会变化,可能带来意想不到的后果,对于需要synchronized不同对象的情况,建议的做法是为每个对象构建一个Object锁来synchronized(不建议对同一个引用反复赋值)。当然将synchronized作为修饰符修饰方法就不会有引用变化的问题,但是这种做法在方法体较大时容易违反第二个原则。
b)
尽可能把synchronized范围缩小,线程互斥是以牺牲并发度为代价的,这点大家都懂。
c) 尽量不要在
可变引用上wait()和notify()。
现在需要计算1+2+3+....+30000的和。请采用多线程完成此计算工作,要求如下:
主线程启动三个线程,分别给它们分派以下任务:
线程1:计算1+2+3+...+10000
线程2:计算10001+10002+...+20000
线程3:计算20001+20002+...+30000
等三个线程都完成工作之后,主线程汇总三个工作线程的计算结果,得到最终答案:
1 + 2 + 3 + .... + 30000 = 450015000
/**
*
*/
package test.SyncAdd;
/**
* @projectName:zhngdps
* @packageName: test.SyncAdd
* @ClassName : SyncAddTest
* @createBy :Test
* @createDate :2014-6-5 上午09:03:35
* @useFor :
*
*/
public class SyncAddTest {
private int getAddCount(int begin,int end,String threadName)
{
TestA test1 = new TestA(begin,end);
Thread th1 = new Thread(test1,threadName);
th1.start() ;
/*
* 对线程对象加锁 针对的是同一个类的多个对象的线程
* 使得多线程运行结果可以控制,synchronized用于保护共享数据
*/
synchronized (th1) {
try {
th1.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
return test1.getSum() ;
}
}
public static void main(String[] args) {
SyncAddTest t = new SyncAddTest();
int sum1 = t.getAddCount(0,10000,"th1");
System.out.println(sum1);
int sum2 = t.getAddCount(10001,20000,"th2") ;
System.out.println(sum2);
int sum3 = t.getAddCount(20001,30000,"th3") ;
System.out.println(sum3);
int sum = sum1 + sum2 + sum3 ;
System.out.println(sum);
}
};
class TestA implements Runnable
{
private int begin ;
private int end ;
private int sum = 0;
public TestA(int begin,int end)
{
this.begin = begin ;
this.end = end ;
}
@Override
public void run() {
add();
System.out.println(Thread.currentThread().getName());
}
private void add()
{
for(int i=begin;i<=end;i++)
{
sum += i ;
}
}
public int getSum()
{
return this.sum ;
}
};
使用while true的方式进行阻塞主函数从而使线程继续执行直到线程执行完毕
class ThTest implements Runnable {
private int start;
private int end;
private int sum = 0;
private boolean isComplete = false;
public boolean isComplete() {
return isComplete;
}
public ThTest() {
super();
}
public ThTest(int start, int end) {
this.start = start;
this.end = end;
}
public int getSum() {
return this.sum;
}
@Override
public void run() {
synchronized (this) {
for (int i = start; i <= end; i++) {
sum += i;
}
isComplete = true;
}
}
public static void main(String[] args) {
ThTest thTest01 = new ThTest(1, 50000);
ThTest thTest02 = new ThTest(50001, 100000);
Thread thread01 = new Thread(thTest01);
Thread thread02 = new Thread(thTest02);
ExecutorService threaPool = Executors.newCachedThreadPool();
threaPool.execute(thread01);
threaPool.execute(thread02);
while (true) {
System.out.print("");
if (thTest01.isComplete() && thTest02.isComplete()) {
break;
}
}
System.out.println("总数为:" + (thTest01.getSum() + thTest02.getSum()));
threaPool.shutdown();
}
};