synchronized关键字
作用:
1. 修饰代码块,被修饰的代码块称为同步语句块,其作用范围是{}括起来的代码,作用的对象是调用这个代码块的对象
2. 修饰非静态方法,被修饰的方法称为同步方法,其作用范围是整个方法,作用的对象是调用这个方法的对象
3. 修饰静态方法,其作用范围是整个静态方法,作用的对象是这个类所有的对象
4. 修饰类,其作用的范围是synchronized后面括起来的部分,作用的对象是这个类的所有对象
对代码块加锁
代码
public class ThreadSynchronize implements Runnable {
public void run() {
synchronized (this) {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "synchronized loop" + i);
}
}
}
public static void main(String[] args) {
ThreadSynchronize t1 = new ThreadSynchronize();
Thread ta = new Thread(t1, "A");
Thread tb = new Thread(t1, "B");
ta.start();
tb.start();
}
}
结果
Asynchronized loop0
Asynchronized loop1
Asynchronized loop2
Asynchronized loop3
Asynchronized loop4
Bsynchronized loop0
Bsynchronized loop1
Bsynchronized loop2
Bsynchronized loop3
Bsynchronized loop4
由代码可以得出结论:当两个并发进程访问同一个对象的由synchronized (this)修饰地代码块时,一次只能有一个线程得到这个代码块,另一个必须等待
注意:是两个线程访问同一个对象的,同一个对象的,同一个对象的!
将main函数改为如下如下代码:
ThreadSynchronize t1 = new ThreadSynchronize();
ThreadSynchronize t2 = new ThreadSynchronize();
Thread ta = new Thread(t1, "A");
Thread tb = new Thread(t2, "B");
ta.start();
tb.start();
得到结果
Asynchronized loop0
Bsynchronized loop0
Asynchronized loop1
Bsynchronized loop1
Asynchronized loop2
Asynchronized loop3
Bsynchronized loop2
Asynchronized loop4
Bsynchronized loop3
Bsynchronized loop4
也就是说,当不同线程要访问不同对象的同一个代码块时,synchronized不会起到阻塞效果
代码
public class ThreadSynchronize {
public void m4t1() {
synchronized (this) {
int i = 5;
while(i-- > 0){
System.out.println(Thread.currentThread().getName() + ": " + i);
try{
Thread.sleep(500);
}catch(InterruptedException ie){
}
}
}
}
public void m4t2(){
int i =5;
while(i-- > 0){
System.out.println(Thread.currentThread().getName() + ": " + i);
try{
Thread.sleep(500);
}catch(InterruptedException ie){
}
}
}
public static void main(String[] args) {
ThreadSynchronize t1 = new ThreadSynchronize();
Thread ta = new Thread(new Runnable() {
@Override
public void run() {
t1.m4t1();
}
},"ta");
Thread tb = new Thread(new Runnable() {
@Override
public void run() {
t1.m4t2();
}
},"tb");
ta.start();
tb.start();
}
}
结果
tb: 4
ta: 4
tb: 3
ta: 3
ta: 2
tb: 2
ta: 1
tb: 1
tb: 0
ta: 0
结果表明:当一个线程访问一个对象的synchronized(this) 代码块时,另一个线程可以访问该对象的非synchronized(this) 修饰的代码块(不同函数中的)
将m4t2()修改得与m4t1()相同,即都用synchronized(this)修饰后,得到结果
ta: 4
ta: 3
ta: 2
ta: 1
ta: 0
tb: 4
tb: 3
tb: 2
tb: 1
tb: 0
结果表明:当一个线程访问到了一个对象的synchronized(this)修饰的代码块时,其他所有线程对该对象的synchronized(this)修饰的代码块的访问都会被阻塞,此时称该线程获取了该对象的对象锁,使得其他线程都不能在此时访问同步代码块
对指定某个对象加锁
public class ThreadSynchronize {
public static void main(String[] args) {
Account account = new Account("zhangsan", 10000);
AccountOperator accountOperator = new AccountOperator(account);
final int THREAD_NUM = 5;
Thread[] threads = new Thread[THREAD_NUM];
for (int i = 0; i < THREAD_NUM; i++) {
threads[i] = new Thread(accountOperator, "Thread" + i);
threads[i].start();
}
}
}
class Account {
String name;
float amount;
public Account(String name, float amount) {
this.name = name;
this.amount = amount;
}
public void deposit(float amt) {
amount += amt;
try{
Thread.sleep(100);
} catch (InterruptedException e){
}
}
public void withdraw(float amt) {
amount -= amt;
try {
Thread.sleep(100);
} catch(InterruptedException e){
}
}
public float get() {
return amount;
}
}
class AccountOperator implements Runnable {
private Account account;
public AccountOperator(Account account) {
this.account = account;
}
@Override
public void run() {
// TODO Auto-generated method stub
synchronized(account){
account.deposit(500);
account.withdraw(300);
System.out.println(Thread.currentThread().getName() + " : " + account.get());
}
}
}
输出结果
Thread0 : 10200.0
Thread3 : 10400.0
Thread4 : 10600.0
Thread2 : 10800.0
Thread1 : 11000.0
在run方法里,我们用synchronized给account对象加了锁,此时,其他想要访问也对account加了锁的区域的线程将会被阻塞
修饰一个非静态方法
public synchronized void run() {
// TODO Auto-generated method stub
account.deposit(500);
account.withdraw(300);
System.out.println(Thread.currentThread().getName() + " : " + account.get());
}
表示该方法一次只能让一个对象调用,与之前一个表示方式等价
修饰静态方法
很明显,静态方法是属于类的,因此,静态方法可以保证同一个类的不同实例之间保持同步
public class ThreadSynchronize implements Runnable {
public void run() {
method();
}
public static synchronized void method(){
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "synchronized loop" + i);
}
}
public static void main(String[] args) {
ThreadSynchronize t1 = new ThreadSynchronize();
ThreadSynchronize t2 = new ThreadSynchronize();
Thread ta = new Thread(t1, "A");
Thread tb = new Thread(t2, "B");
ta.start();
tb.start();
}
}
输出结果为
Asynchronized loop0
Asynchronized loop1
Asynchronized loop2
Asynchronized loop3
Asynchronized loop4
Bsynchronized loop0
Bsynchronized loop1
Bsynchronized loop2
Bsynchronized loop3
Bsynchronized loop4
修饰一个类
很明显,修饰一个类的时候,该类的所有实例公用同一把锁