synchronized是java中的关键字,是一中同步锁。修饰的对象有以下几种:
1、修饰一个代码块:被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
2、修饰一个方法:被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象。
3、修饰一个静态的方法:作用范围是整个静态方法,作用的对象是这个类的所有对象。
4、修饰一个类:其作用的范围是synchronized后面括号部分,最用对象和静态方法一样,是这个类的所有对象。
一、修饰一个代码块
package com.multithread.test;
public class SyncThread implements Runnable{
private static int count;
public SyncThread() {
count = 0;
}
@Override
public void run() {
synchronized(this){
for (int i = 0; i < 5; i++){
System.out.println(Thread.currentThread().getName()+":"+(count++));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public int getCount(){
return count;
}
}
package com.multithread.learning.Main;
import com.multithread.test.SyncThread;
public class MainSyncThread {
public static void main(String[] args) {
SyncThread st1 = new SyncThread();
new Thread(st1,"SyncThread1").start();
new Thread(st1,"SyncThread2").start();
}
}
SyncThread1:0
SyncThread1:1
SyncThread1:2
SyncThread1:3
SyncThread1:4
SyncThread2:5
SyncThread2:6
SyncThread2:7
SyncThread2:8
SyncThread2:9
当两个并发线程(thread1和thread2)访问同一个对象(syncThread)中的synchronized代码块时,在同一时刻只能有一个线程得到执行,另一个线程受阻塞,必须等待当前线程执行完这个代码块以后才能执行该代码块。Thread1和thread2是互斥的,因为在执行synchronized代码块时会锁定当前的对象,只有执行完该代码块才能释放该对象锁,下一个线程才能执行并锁定该对象。
稍微修改一下:创建两个对象,也就是说有**两把锁**,结果如下:
```java
SyncThread st1 = new SyncThread();
SyncThread st2 = new SyncThread();
new Thread(st1,"SyncThread1").start();
new Thread(st2,"SyncThread2").start();
SyncThread1:0
SyncThread2:1
SyncThread1:3
SyncThread2:2
SyncThread1:4
SyncThread2:5
SyncThread1:6
SyncThread2:6
SyncThread1:7
SyncThread2:7
两把锁分别锁定syncThread1对象和syncThread2对象,两把锁互不干扰,不形成互斥,两个线程同时进行。
此处的this相当于一个对象,指向当前对象(如此便相当于锁定了一个方法)。如果需要对一个对象加锁,如下:
syncThreadObject s = new syncThreadObject("黄",23);
SyncThread st1 = new SyncThread(s);
for (int i = 0; i < 5; i++) {
new Thread(st1, " SyncThread+"+i).start();
}
@Override
public void run() {
synchronized(s){
for (int i = 0; i < 5; i++){
System.out.println(Thread.currentThread().getName()+":"+s.toString()+(count++));
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
循环创建对象st1的线程5个,执行,每个线程访问st1对象时,其他试图访问st1对象的线程将会阻塞,直到该线程访问st1对象结束。也就是说谁拿到那个锁谁就可以运行锁内控制的代码。
因此在类似于需要多个线程按顺序打印序号时,便可以让多个线拥有共同的一个锁,或者使用wait/notify来控制。
二、修饰一个方法
修饰一个方法很简单,就是在方法前面加上synchronized关键字,public synchronized void method(){}。
注意:synchronized方法不能被继承,也就是覆写了父类的syn方法,默认情况下不是同步的,必须显示地在子类的这个方法加上synchronized关键字才行.
三、修饰一个静态方法
@Override
public void run() {
method();
}
public synchronized static void method(){
for (int i = 0; i < 5; i++){
System.out.println(Thread.currentThread().getName()+":"+(count++));
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
SyncThread st1 = new SyncThread(s);
SyncThread st2 = new SyncThread(s);
SyncThread st3 = new SyncThread(s);
new Thread(st1, "A").start();
new Thread(st2, "B").start();
new Thread(st3, "C+").start();
A:0
A:1
A:2
A:3
A:4
C+:5
C+:6
C+:7
C+:8
C+:9
B:10
B:11
B:12
B:13
B:14
即使是创建了多个对象,又多个线程分别访问每个对象,但还是保持了线程同步。因为run中调用了静态方法method,而静态方法时属于类的,因此,这些对象拥有的锁是同一把锁。
四、修饰一个类
类似于静态方法。此处不再阐述。
网友评论