利用synchronized关键字是最简单的实现同步的方式,synchronized可以用于方法,代码块,synchronized可以保证在同一时刻,只有一个线程可以执行某个方法或某个代码块,同时synchronized可以保证一个线程的变化可见。也就是保证了临界区某一时刻只能被一个线程访问(被synchronized修饰的方法,或者代码块都是临界区)。当一个线程进入了临界区,其他试图访问该临界区的线程将会被挂起,知道第一个线程执行完正在运行的方法。
synchronized的使用:
- 普通方法,锁是当前对象的实例
- 静态方法,锁是当前类的class对象
- 同步方法块,锁是括号里面的对象。
注意:
对于静态同步方法存在这样一种情况,因为锁是当前类的class对象,所以同一时间只能有一个线程访问,但是对于其他的普通方法,其他线程也是可以访问修改的,如果其他方法中对临界区中的数据进行了修改,也会造成数据的不一致。
代码示例讲解,最简单的例子是对一个数进行加减法。
普通方法
// add del 方法都是临界区
public class Demo8 {
public static void main(String[] args) {
long number = 100;
NumberData numberData = new NumberData(number);
Thread thread1 = new Thread(new User(numberData, 10));
Thread thread2 = new Thread(new User(numberData, -50));
Thread thread3 = new Thread(new User(numberData, 10));
Thread thread4 = new Thread(new User(numberData, -10));
Thread thread5 = new Thread(new User(numberData, -40));
Thread thread6 = new Thread(new User(numberData, 10));
Thread thread7 = new Thread(new User(numberData, -10));
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
thread6.start();
thread7.start();
}
static class NumberData implements Serializable{
private long number;
public NumberData(long number) {
this.number = number;
}
public long getNumber() {
return number;
}
public void setNumber(long number) {
this.number = number;
}
public synchronized void add(long num) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
number = number + num;
System.out.println("=======add============ "+num+" "+number);
}
public synchronized void del(long num) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
number = number + num;
System.out.println("=======del============ "+num+" "+number);
}
}
static class User implements Runnable{
private NumberData numberData;
private long number;
public long getNumber() {
return number;
}
public void setNumber(long number) {
this.number = number;
}
public NumberData getNumberData() {
return numberData;
}
public void setNumberData(NumberData numberData) {
this.numberData = numberData;
}
public User(NumberData numberData,long num) {
super();
this.numberData = numberData;
this.number = num;
}
@Override
public void run() {
if (number > 0) {
numberData.add(number);
}else {
numberData.del(number);
}
}
}
}
同步代码块:
public class Demo8 {
public static void main(String[] args) {
long number = 100;
NumberData numberData = new NumberData(number);
Thread thread1 = new Thread(new User(numberData, 10));
Thread thread2 = new Thread(new User(numberData, -50));
Thread thread3 = new Thread(new User(numberData, 10));
Thread thread4 = new Thread(new User(numberData, -10));
Thread thread5 = new Thread(new User(numberData, -40));
Thread thread6 = new Thread(new User(numberData, 10));
Thread thread7 = new Thread(new User(numberData, -10));
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
thread6.start();
thread7.start();
}
static class NumberData implements Serializable{
private long number;
public NumberData(long number) {
this.number = number;
}
public long getNumber() {
return number;
}
public void setNumber(long number) {
this.number = number;
}
public void add(long num) {
synchronized (this) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
number = number + num;
System.out.println("=======add============ "+num+" "+number);
}
}
public void del(long num) {
synchronized (this) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
number = number + num;
System.out.println("=======del============ "+num+" "+number);
}
}
}
static class User implements Runnable{
private NumberData numberData;
private long number;
public long getNumber() {
return number;
}
public void setNumber(long number) {
this.number = number;
}
public NumberData getNumberData() {
return numberData;
}
public void setNumberData(NumberData numberData) {
this.numberData = numberData;
}
public User(NumberData numberData,long num) {
super();
this.numberData = numberData;
this.number = num;
}
@Override
public void run() {
if (number > 0) {
numberData.add(number);
}else {
numberData.del(number);
}
}
}
}
或者设置一个公共的对象,作为统一的一个锁。
静态同步方法:
public class Demo9 {
public static void main(String[] args) {
long number = 100;
NumberData numberData = new NumberData(number);
Thread thread1 = new Thread(new User(numberData, 10));
Thread thread2 = new Thread(new User(numberData, -50));
Thread thread3 = new Thread(new User(numberData, 10));
Thread thread4 = new Thread(new User(numberData, -10));
Thread thread5 = new Thread(new User(numberData, -40));
Thread thread6 = new Thread(new User(numberData, 10));
Thread thread7 = new Thread(new User(numberData, -10));
Thread thread8 = new Thread() {
@Override
public void run() {
NumberData.staticFun1();
}
};
Thread thread9 = new Thread() {
@Override
public void run() {
NumberData.staticFun2();
}
};
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
thread6.start();
thread7.start();
thread8.start();
thread9.start();
}
static class NumberData implements Serializable{
private long number;
public NumberData(long number) {
this.number = number;
}
public long getNumber() {
return number;
}
public void setNumber(long number) {
this.number = number;
}
public void add(long num) {
synchronized (this) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
number = number + num;
System.out.println("=======add============ "+num+" "+number);
}
}
public void del(long num) {
synchronized (this) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
number = number + num;
System.out.println("=======del============ "+num+" "+number);
}
}
public static synchronized void staticFun1() {
for(int i=0;i<4;i++) {
try {
Thread.sleep(500);
System.out.println("========staticFun1========");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static synchronized void staticFun2() {
for(int i=0;i<4;i++) {
try {
Thread.sleep(500);
System.out.println("========staticFun2========");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class User implements Runnable{
private NumberData numberData;
private long number;
public long getNumber() {
return number;
}
public void setNumber(long number) {
this.number = number;
}
public NumberData getNumberData() {
return numberData;
}
public void setNumberData(NumberData numberData) {
this.numberData = numberData;
}
public User(NumberData numberData,long num) {
super();
this.numberData = numberData;
this.number = num;
}
@Override
public void run() {
if (number > 0) {
numberData.add(number);
}else {
numberData.del(number);
}
}
}
}
result:
=======add============ 10 110
=======del============ -10 100
=======add============ 10 110
=======del============ -40 70
========staticFun1========
=======del============ -10 60
=======add============ 10 70
=======del============ -50 20
========staticFun1========
========staticFun1========
========staticFun1========
========staticFun2========
========staticFun2========
========staticFun2========
========staticFun2========
对于static方法synchronized锁的对象是当前类的class对象,所以和普通的synchronized方法不存在互斥问题,可以同时执行,但对于同步static方法,同时只能有一个执行。