synchronized同步方法
- 1.提出问题-实例变量非线程安全
- 1.1 何为非线程安全?
- 1.2 举例
- 1.2.1 有私有变量的类HasPrivateNum (供多线程们去调用)
- 1.2.2 线程A
- 1.2.3 线程B
- 1.2.4 开启AB线程共同访问1个对象
- 1.2.5 执行结果(多次执行有几率出现如下结果)
- 2. 解决问题-给方法上加synchronized
- 2.1 synchronized修饰范围
- 2.2 修改后的HasPrivateNum类
- 2.3 执行结果(多次执行一定是这样)
- 3.思考问题-如果是多个对象的锁
- 3.1 修改Run类
- 3.2 运行结果
- 4.思考问题-非synchronized方法会锁着吗
- 4.1修改HasPrivateNum类
- 4.2修改线程B调用非synchronized方法
- 4.3 run方法
- 4.4 运行结果
1.提出问题-实例变量非线程安全
如果多个线程同时访问1个对象的实例变量,则可能出现"非线程安全"问题。
1.1 何为非线程安全?
我的理解是多个线程对一个实例变量操作会出现值被更改,不同步的情况。
1.2 举例
1.2.1 有私有变量的类HasPrivateNum (供多线程们去调用)
public class HasPrivateNum {
private int num = 0;
public void addNum(String userName){
try{
if (userName.equalsIgnoreCase("wang.dong")){
num = 1;
System.out.println("wang dong set over");
Thread.sleep(2000);
}else {
num = 2;
System.out.println("other man set over");
}
System.out.println(userName + " num = " + num);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
这个类里面有一个私有变量 num,在addNum()函数里根据传的userName不同而赋值.
1.2.2 线程A
public class ThreadA extends Thread{
private HasPrivateNum num;
public ThreadA(HasPrivateNum num){
super();
this.num = num;
}
@Override
public void run(){
super.run();
num.addNum("wang.dong");
}
}
1.2.3 线程B
public class ThreadB extends Thread{
private HasPrivateNum num;
public ThreadB(HasPrivateNum num){
super();
this.num = num;
}
@Override
public void run(){
super.run();
num.addNum("other man");
}
}
1.2.4 开启AB线程共同访问1个对象
public class Run {
public static void main(String[] args) {
HasPrivateNum numRef = new HasPrivateNum();
//A
ThreadA aThread = new ThreadA(numRef);
aThread.start();
//B
ThreadB bThread = new ThreadB(numRef);
bThread.start();
}
}
1.2.5 执行结果(多次执行有几率出现如下结果)
A和B这2个线程同时访问一个没有同步的方法,并给里面变量赋值,可能出现"非线程安全"问题
2. 解决问题-给方法上加synchronized
2.1 synchronized修饰范围
修饰对象 | 作用范围 | 作用对象 |
代码块 | synchronized(this){}内 | 调用这个代码块的对象 |
方法(接口方法/构造方法不行) | 整个方法 | 调用这个方法的实例对象 |
静态方法 | 整个方法 | 这个类的所有类对象(共用一把锁) |
类 | synchronized后面{} | 这个类的所有对象(共用一把锁) |
2.2 修改后的HasPrivateNum类
public class HasPrivateNum {
private int num = 0;
// add synchroized
public synchronized void addNum(String userName){
try{
if (userName.equalsIgnoreCase("wang.dong")){
num = 1;
System.out.println("wang dong set over");
Thread.sleep(2000);
}else {
num = 2;
System.out.println("other man set over");
}
System.out.println(userName + " num = " + num);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
2.3 执行结果(多次执行一定是这样)
如图说明线程B是等待线程A执行完毕后并释放了锁,才能获取锁
3.思考问题-如果是多个对象的锁
在上面1.2.4里只定义了一个HasPrivateNum的对象,如果有个HasPrivateNum对象,AB线程范围不同的对象,会是同步还是异步呢?
3.1 修改Run类
public class RunTwo {
public static void main(String[] args) {
HasPrivateNum numRef_1 = new HasPrivateNum();
HasPrivateNum numRef_2 = new HasPrivateNum();
//A
ThreadA aThread = new ThreadA(numRef_1);
aThread.start();
//B
ThreadB bThread = new ThreadB(numRef_2);
bThread.start();
}
}
A线程和B线程分别用不同的对象
3.2 运行结果
因为A线程睡了2秒,说是后打印的,这个2个线程是异步运行的,不相互影响
这个结果说明关键字synchronized的锁是对象锁,不是把一段代码或函数锁住
4.思考问题-非synchronized方法会锁着吗
一个对象有synchronized方法和非synchronized方法,如果线程A占用了synchronized方法,线程B是否可以访问这个对象的非synchronized方法?
4.1修改HasPrivateNum类
public class HasPrivateNum {
private int num = 0;
// add synchroized
public synchronized void addNum(String userName){
try{
if (userName.equalsIgnoreCase("wang.dong")){
num = 1;
System.out.println("wang dong set over");
Thread.sleep(2000);
}else {
num = 2;
System.out.println("other man set over");
}
System.out.println(userName + " num = " + num);
}catch (InterruptedException e){
e.printStackTrace();
}
}
// not synchronized
public void anotherMethod(){
try{
System.out.println(Thread.currentThread().getName() + " anotherMethod begin");
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + " anotherMethod end");
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
4.2修改线程B调用非synchronized方法
public class ThreadB extends Thread{
private HasPrivateNum num;
public ThreadB(HasPrivateNum num){
super();
this.num = num;
}
@Override
public void run(){
super.run();
//num.addNum("other man");
num.anotherMethod();
}
}
4.3 run方法
public class Run {
public static void main(String[] args) {
HasPrivateNum numRef = new HasPrivateNum();
//A
ThreadA aThread = new ThreadA(numRef);
aThread.start();
//B
ThreadB bThread = new ThreadB(numRef);
bThread.start();
}
}
4.4 运行结果
从结果看出线程A和线程B是异步执行的
- 多个线程同时访问同一个object的synchronized(this)代码块时,一个时间只有一个线程,其他线程只能等待
- 其他线程可以访问该object的非synchronized(this)代码块
这次暂时写这么多吧,加油!