本文参考自大佬 公众号:路人甲java
添加链接描述
当多个线程操作共享数据时会存在数据安全问题,java提供了synchronized可以帮助我们解决,先来看一段代码
package juc;
/**
* @author yanjun.liu
* @date 2020/6/28--13:21
*/
public class MySynchronized {
private static int sum=0;
public static void m1(){
for(int i=0;i<100000;i++){
sum++;
}
}
public static class T1 extends Thread{
@Override
public void run() {
m1();
}
}
public static void main(String[] args) throws Exception{
T1 t1 = new T1();
T1 t2 = new T1();
T1 t3 = new T1();
t1.start();
t2.start();
t3.start();
//主线程等待,其他线程执行完成,打印sum
t1.join();
t2.join();
t3.join();
System.out.println(sum);
}
}
MySynchronized 中有个静态变量sum,默认值是0,m1()方法中对sum++执行100000次,main方法中创建了3个线程用来调用m1()方法,然后调用3个线程的join()方法,用来等待3个线程执行完毕之后,打印sum的值。我们期望的结果是300000,运行一下,但真实的结果却不是300000。上面的程序在多线程中表现出来的结果和预想的结果不一致,说明上面的程序不是线程安全的。
使用synchronized来修饰静态方法
package juc;
/**
* @author yanjun.liu
* @date 2020/6/28--13:21
* 对于操作共享的资源数据,需要注意数据的安全问题
*/
public class MySynchronized2 {
private static int sum=0;
/**
* synchronized饰静态方法,作用于类的Class对象,进入修饰的静态方法前需要先获取类的Class对象的锁
*/
public synchronized static void m1(){
for(int i=0;i<100000;i++){
sum++;
}
}
public static class T1 extends Thread{
@Override
public void run() {
m1();
}
}
public static void main(String[] args) throws Exception{
T1 t1 = new T1();
T1 t2 = new T1();
T1 t3 = new T1();
t1.start();
t2.start();
t3.start();
//主线程等待,其他线程执行完成,打印sum
t1.join();
t2.join();
t3.join();
System.out.println(sum);
}
}
加上synchronized修饰会发现输出结构正确300000
使用synchronized来修饰非静态方法(普通方法)
package juc;
/**
* @author yanjun.liu
* @date 2020/6/28--13:21
*/
public class MySynchronized {
private static int sum=0;
/**
* synchronized修饰实例方法,作用于当前实例,进入同步代码前需要先获取实例的锁
*/
public synchronized void m1(){
for(int i=0;i<100000;i++){
sum++;
}
}
public static class T1 extends Thread{
private MySynchronized mySynchronized;
public T1(MySynchronized mySynchronized){
this.mySynchronized=mySynchronized;
}
@Override
public void run() {
mySynchronized.m1();
}
}
public static void main(String[] args) throws Exception{
MySynchronized mySynchronized = new MySynchronized();
//锁实例对象必须是同一个
T1 t1 = new T1(mySynchronized);
T1 t2 = new T1(mySynchronized);
T1 t3 = new T1(mySynchronized);
t1.start();
t2.start();
t3.start();
//主线程等待,其他线程执行完成,打印sum
t1.join();
t2.join();
t3.join();
System.out.println(sum);
}
}
结果输出正常300000
m1()方法是实例方法,三个线程操作m1()时,需要先获取mySynchronized 的锁,没有获取到锁的,将等待,直到其他线程释放锁为止
实例方法上加synchronized,线程安全的前提是,多个线程操作的是同一个实例,如果多个线程作用于不同的实例,那么线程安全是无法保证的
同一个实例的多个实例方法上有synchronized,这些方法都是互斥的,同一时间只允许一个线程操作同一个实例的其中的一个synchronized方法
synchronized同步代码块
package juc;
/**
* @author yanjun.liu
* @date 2020/6/28--13:21
*/
public class MySynchronized {
private static int sum=0;
private static Integer lock= new Integer(2);
/**
* synchronized修饰代码块
*/
public static class T1 extends Thread{
private Integer lock;
public T1(Integer lock){
this.lock=lock;
}
@Override
public void run() {
//修饰代码块
synchronized(lock){
for(int i=0;i<100000;i++){
sum++;
}
}
}
}
public static void main(String[] args) throws Exception{
T1 t1 = new T1(lock);
T1 t2 = new T1(lock);
T1 t3 = new T1(lock);
t1.start();
t2.start();
t3.start();
//主线程等待,其他线程执行完成,打印sum
t1.join();
t2.join();
t3.join();
System.out.println(sum);
}
}