Java中synchronized关键字作用是实现线程间的同步。它对同步的代码加锁,使得每次只能有一个线程进入同步快,以此保证线程间的安全性。 它的用法主要包括:
以下例子,展现synchronized的作用:
两个线程同时对一个类变量累加十万次,最后结果往往小于二十万次。因为两个线程对同一个类变量进行写入的时候,一个线程的结果会覆盖另外一个。
package temp;
public class AccountingVol implements Runnable{
static AccountingVol instance = new AccountingVol();
static volatile int i = 0;
public static void increase() {
i++;
}
@Override
public void run() {
for(int j = 0; j < 100000; j++) {
increase();
}
}
public static void main (String[] args) throws InterruptedException{
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();t2.start();
t1.join();t2.join();
System.out.println(i);
}
}
以上代码执行结果(可能):
151018
public class AccountingVol implements Runnable{
static AccountingVol instance = new AccountingVol();
static volatile int i = 0;
public static void increase() {
i++;
}
@Override
public void run() {
synchronized(this) {
for(int j = 0; j < 100000; j++) {
increase();
}
System.out.println(Thread.currentThread().getName()+ " complete! i = " + i );
}
}
public static void main (String[] args) throws InterruptedException{
Thread t1 = new Thread(instance ,"A");
Thread t2 = new Thread(instance, "B");
t1.start();t2.start();
t1.join();t2.join();
System.out.println(i);
}
}
以上代码会产生阻塞,等一个线程执行完后才会执行另一个,执行结果为:
/*
* A complete! i = 100000
* B complete! i = 200000
* 200000
*/
当一个线程访问对象的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该对象中的非synchronized(this)同步代码块。
class Count implements Runnable {
private int count;
public Count() {
count = 0;
}
public void countAdd() {
synchronized (this) {
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + (count++));
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// 非synchronized代码块,未对count进行读写操作,所以可以不用synchronized
public void printCount() {
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + " count:" + count);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void run() {
String threadName = Thread.currentThread().getName();
if (threadName.equals("A")) {
countAdd();
} else if (threadName.equals("B")) {
printCount();
}
}
// main函数略
}
以上代码执行结果为:
A:0
B count:1
B count:1
A:1
B count:2
A:2
B count:3
A:3
A:4
B count:5
修饰实例或者实例方法,会获取对实例的锁,每次只有一个线程对实例进行访问。 一下两种方法都能正确得到200000.
public class AccountingVol implements Runnable {
static AccountingVol instance = new AccountingVol();
static volatile int i = 0;
public synchronized void increase() {
i++;
}
@Override
public void run() {
for (int j = 0; j < 100000; j++) {
increase();
}
}
// main方法略
}
public class AccountingVol implements Runnable {
static AccountingVol instance = new AccountingVol();
static volatile int i = 0;
@Override
public void run() {
for (int j = 0; j < 100000; j++) {
synchronized(instance) {
i++;
}
}
}
// main方法略
}
静态方法是属于类的,因此synchronized 修饰静态方法会使多个调用该方法(调用该类资源)的线程使用同一把锁。
class Count implements Runnable {
private static int count;
public Count() {
count = 0;
}
public synchronized static void method() {
for (int i = 0; i < 5; i ++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + (count++));
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void run() {
method();
}
// main函数略
}
以上代码执行结果为:
SyncThread2:0
SyncThread2:1
SyncThread2:2
SyncThread2:3
SyncThread2:4
SyncThread1:5
SyncThread1:6
SyncThread1:7
SyncThread1:8
SyncThread1:9
Synchronized还可修饰一个类T,类T的所有对象使用同一把锁:
class Count implements Runnable {
private static int count;
public Count() {
count = 0;
}
public static void method() {
synchronized (Count.class) {
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + (count++));
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public synchronized void run() {
method();
}
// main函数略
}
执行结果同3中例子一样。