Java线程同步-动力节点

线程安全问题

在多线程程序中,当多个线程同时操作堆区/方法区同一个数据时,可能引发数据不一致的现象, 称为线程安全问题。

出现线程安全问题, 怎么办?

让每个线程都访问自己的局部变量, 不会产生线程安全问题

如果多个线程必须同时操作堆区/方法区同一个数据 , 采用线程同步技术

线程如何同步?

语法:

synchronized ( 锁对象 ) {

同步代码块

}

工作原理:

● 线程要执行同步代码块,必须先获得锁对象

● 任意对象都可以作为锁对象, 任意对象都有一个内置锁

● 一个锁对象最多被一个线程持有

● 线程持有了锁对象后,会一直持有, 直到执行完同步代码块后才会释放锁对象

package com.wkcto.chapter07.sync.p2;
/**

  • 银行帐户类
  • @author 蛙课网

*/
public class BankAccount {
int balance = 10000 ; //余额 ,单位:万元
private static final Object OBJ = new Object(); //常量

//取钱的操作, 约定, 每次取钱1000
public void withdraw() {
	synchronized ( OBJ ) { 		//一般使用常量作为锁对象
		System.out.println(Thread.currentThread().getName() +  "取钱 前, 余额为:" + balance);
		balance -= 1000;
		System.out.println(Thread.currentThread().getName() + "取了1000万后, 余额为:" + balance);
	}
	/*
	 * 1) xiaoming获得了CPU执行权, 执行withdraw()方法, 先获得OBJ锁对象, 执行同步代码块
	 * 2) xiaoming在执行同步代码块期间, CPU执行权被baby抢走了, xiaoming转为就绪状态
	 * 		babay获得CPU执行权, 要也执行同步代码块, 必须先获得OBJ锁对象,
	 * 		现在OBJ锁对象被xiaoming持有, baby线程转到等待锁对象池中阻塞
	 * 3) xiaoming重新获得CPU执行权, 继续执行同步代码块, 执行完同步代码块后, 释放OBJ锁对象
	 * 4) 等待锁对象池中的baby如果获得了锁对象, 转为就绪状态
	 */
}

}

package com.wkcto.chapter07.sync.p2;
/**

  • 定义一个线程类,模拟 从银行帐户 中取钱
  • @author 蛙课网

*/
public class PersonThread extends Thread {
private BankAccount bankaccount; //银行帐户

public PersonThread(BankAccount bankaccount) {
	super();
	this.bankaccount = bankaccount;
}

@Override
public void run() {
	bankaccount.withdraw();
}

}

package com.wkcto.chapter07.sync.p2;
/**

  • 使用线程模拟多人同时从某一帐户中取钱
  • 线程同步
  • @author 蛙课网

*/
public class Test01 {

public static void main(String[] args) {
	//先开户
	BankAccount account = new BankAccount();
	
	//定义三个线程模拟三个人, 是从同一个帐户中取钱 
	PersonThread xiaoming = new PersonThread(account);
	PersonThread bingbing = new PersonThread(account);
	PersonThread baby = new PersonThread(account);
	
	xiaoming.setName("xiaoming");
	bingbing.setName("bingbing");
	baby.setName("baby");
	
	xiaoming.start();
	bingbing.start();
	baby.start();
	
}

}

同步代码块

同步代码块要想实现同步,必须保证使用同一个锁对象

只要使用了同一个锁对象的同步代码块就可以同步

package com.wkcto.chapter07.sync.p3;
/**

  • 同步代码块, 只要使用相同的锁对象就可以实现同步
  • @author 蛙课网

*/
public class Test01 {
public static void main(String[] args) {
PrintNum pNum = new PrintNum();

	//创建线程,调用m1()
	new Thread(new Runnable() {
		@Override
		public void run() {
			pNum.m1();
		}
	}).start();
	
	//创建线程,调用m2()
	new Thread(new Runnable() {
		@Override
		public void run() {

// pNum.m2(); //当使用this对象作为锁对象时, 可以同步
new PrintNum().m2(); //使用this作为锁对象, 不能同步, 与第一个线程的锁对象不是一个
}
}).start();
}
}

package com.wkcto.chapter07.sync.p3;
/**

  • 定义类
  • 提供两个 方法,分别打印字符串
  • @author 蛙课网

*/
public class PrintNum {
private static final Object OBJ = new Object(); //定义常量

public void m1() {

// synchronized (OBJ) { //经常使用常量作为锁对象
synchronized ( this ) { //有时也会使用this作为锁对象 , 就是调用m1()方法的对象
for(int i = 1; i<=200; i++){
System.out.println(“wkcto is NB website”);
}
}
}

public void m2() {

// synchronized (OBJ) {
synchronized (this) {
for(int i = 1; i<=200; i++){
System.out.println(“bjpowernode is a good school”);
}

	}
}

}

ackage com.wkcto.chapter07.sync.p4;
/**

  • 使用当前类的运行时类作为锁对象
  • @author 蛙课网

*/
public class Test02 {

public static void main(String[] args) {
	//创建线程, 打印wkcto
	new Thread(new Runnable() {
		@Override
		public void run() {
			while( true ){
				printText("wkcto");
			}
		}
	}).start();
	
	//创建线程, 打印bjpowernode
	new Thread(new Runnable() {
		@Override
		public void run() {
			while( true ){
				printText("bjpowernode");
			}
		}
	}).start();
}

private static final Object OBJ = new Object();	//常量 

//静态方法,打印一个字符串
public static void printText( String  text) {

// synchronized (OBJ) {
synchronized ( Test02.class ) { //使用当前类的运行时类对象作为锁对象, 有人把它称为类锁
//可以简单的理解 为把当前类的字节码文件作为锁对象
for( int i = 0 ; i<text.length() ; i++){
System.out.print( text.charAt(i));
}
System.out.println();
}

}

}

同步方法

package com.wkcto.chapter07.sync.p5;
/**

  • 同步实例方法, 就是把整个方法体作为同步代码块, 默认锁对象 是this对象
    */
    public class Test01 {

    public static void main(String[] args) {
    Test01 obj = new Test01();

     //创建线程, 调用m1()
     new Thread(new Runnable() {
     	@Override
     	public void run() {
     		obj.m1();
     	}
     }).start();
     
     //创建线程, 调用m2()
     new Thread(new Runnable() {
     	@Override
     	public void run() {
     		obj.m2();
     	}
     }).start();
    

    }

    /*

    • 把整个方法体作为同步代码块,并且使用this作为锁对象时, 可以直接使用synchronized修饰方法, 称为同步方法
    • 同步实例方法, 就是把整个方法体作为同步代码块, 默认锁对象 是this对象
      */
      public synchronized void m1() {
      for(int i =1; i<=500; i++){
      System.out.println( Thread.currentThread().getName() + “–>” + i);
      }
      }

    public void m2() {
    synchronized ( this ) {
    for(int i =1; i<=500; i++){
    System.out.println( Thread.currentThread().getName() + “======>” + i);
    }
    }
    }

}

package com.wkcto.chapter07.sync.p5;
/**

  • 同步静态方法, 就是把整个方法体作为同步代码块, 默认锁对象 是当前类的运行时类对象
    */
    public class Test02 {

    public static void main(String[] args) {

     //创建线程, 调用m1()
     new Thread(new Runnable() {
     	@Override
     	public void run() {
     		Test02.m1();
     	}
     }).start();
     
     //创建线程, 调用m2()
     new Thread(new Runnable() {
     	@Override
     	public void run() {
     		Test02.m2();
     	}
     }).start();
    

    }

    /*

    • 把整个方法体作为同步代码块,并且使用当前类的运行时类对象(Test02.class)作为锁对象时, 可以直接使用synchronized修饰方法, 称为同步方法
    • 同步静态方法, 就是把整个方法体作为同步代码块, 默认锁对象 是当前类的运行时类对象(Test02.class)
      */
      public synchronized static void m1() {
      for(int i =1; i<=500; i++){
      System.out.println( Thread.currentThread().getName() + “–>” + i);
      }
      }

    public static void m2() {
    synchronized ( Test02.class ) {
    for(int i =1; i<=500; i++){
    System.out.println( Thread.currentThread().getName() + “======>” + i);
    }
    }
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值