public class SyThreadTest {
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
while(true){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sythread.sys1("1234567");
}
}
}).start();
new Thread(new Runnable() {
public void run() {
while(true){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sythread.sys1("abcdefg");
}
}
}).start();
}
static class sythread{
public synchronized static void sys1(String name){
for (int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
首先Synchronized这个关键词,是同步的核心,他相当于之后版本的lock.其意思也是锁的意思,这段代码输出的结果不会乱,都是输出“1234567”和”abcdefg“,不会产生"123abc"这类互相参杂的数据。
static class sythread{
public synchronized static void sys1(String name){
for (int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
这里我去掉了Synchronized这个关键词,他相当于没加锁,这时候的运行效果如下图
我来具体说一下此图意思,我们假定A为10,线程1,2同时运行(不考虑处理速度),当线程1运行,获得资源A的值为10,这时候A+1为11,假如这时候线程2还没拿到资源A,那么,等A执行完了在拿到资源A,这样没有问题,线程2会拿到正确的资源A=11,然后11-1=10,这时候情况假如是这样的,这时候11-1没有执行完,还没有给这个资源A,那么线程1下次拿到的资源A还是A=11,然后11+1=12,这时候大家就发现了,和我们想象中需要的不一样。
这时候我们来说说Synchronized在这里的作用是什么,他相当于保证了代码块或者方法的同步,上面已经贴过怎么同步方法,下面代码为同步代码块
public static void sys1(String name){
synchronized(共同对象){
for (int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
这也能达到同样的同步效果,这里要说一下,不要在方法上修饰synchronized又同时在代码块上用此关键词,容易造成死锁,使得程序不继续往下运行,这个应该要避免。
- 对于实例的同步方法,使用this即当前实例对象
- 对于静态的同步方法,使用当前类的字节码对象。
这里还有一个共同对象我要来说一下,这个共同对象见名知意,意思就是这个参数必须是共同的对象,相当于现实中的同一把钥匙,你用钥匙开了门,我就要等你开好门出来,把钥匙给我,我在用这个钥匙去开这个门,假如不是共同的对象应该也好理解,我开我的门,你开你的门,这样就达不到我们要的效果。
也就是说使用同步方法的话,同步锁只能是this或者当前类的字节码对象。所以根据同步锁必须互斥的前提,如果同时使用synchronized代码块和synchronized方法对同一个共享资源进行线程同步,synchronized代码块的同步锁也必须跟synchronized方法一样(要么是this,要么是类的字节码对象通俗说就是class)。