2、 synchronized同步方法

对象及变量的并发访问
1 synchronized同步方法
1.3 方法内部的变量都是不存在线程安全问题,永远都是线程安全的,因为方法内部的变量是私有的特性造成的。
1.4 实例变量就会存在线程安全问题

package thread;

public class HaselfPrivateNum {
	private int num = 0 ;

public void addI(String username) throws InterruptedException {
	if(username.equals("a")) {
		num = 100;
		System.out.println("a set over");
		Thread.sleep(2000);
	} else {
		num = 200;
		System.out.println("b set over");
		
	}
	System.out.println(username + " num = " +num);
}

}

package thread;

public class ThreadA extends Thread {
	private HaselfPrivateNum numref;
	public ThreadA(HaselfPrivateNum numref) {
		super();
		this.numref = numref;
	}
	@Override
	public void run() {
		super.run();
		try {
			numref.addI("a");
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
package thread;

public class ThreadB extends Thread {
	private HaselfPrivateNum numref;
	public ThreadB(HaselfPrivateNum numref) {
		super();
		this.numref = numref;
	}
	@Override
	public void run() {
		super.run();
		try {
			numref.addI("b");
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
package thread;

public class Run {

public static void main(String[] args) {
	HaselfPrivateNum haselfPrivateNum = new HaselfPrivateNum();
	ThreadA A  = new ThreadA(haselfPrivateNum);
	A.start();
	ThreadB B = new ThreadB(haselfPrivateNum);
	B.start();
}

}
 结果展示
a set over
b set over
b num = 200
a num = 200
 添加一个sycnhroized()同步方法

package thread;

public class HaselfPrivateNum {
	private int num = 0 ;

synchronized public void addI(String username) throws InterruptedException {
	if(username.equals("a")) {
		num = 100;
		System.out.println("a set over");
		Thread.sleep(2000);
	} else {
		num = 200;
		System.out.println("b set over");
		
	}
	System.out.println(username + " num = " +num);
}

}
 主方法

package thread;

public class Run {

public static void main(String[] args) {
	HaselfPrivateNum haselfPrivateNum = new HaselfPrivateNum();
	ThreadA A  = new ThreadA(haselfPrivateNum);
	A.start();
	ThreadB B = new ThreadB(haselfPrivateNum);
	B.start();
}

}
结果展示:
b set over
b num = 200
a set over
a num = 100
关键字synchronized取得的锁都是对象锁,而不是把一小段代码方法当做锁,所以线程先执行那个带synchronized关键字的方法,就先获得哪一个对象锁,由于new 了两个实例对象,所以有两个锁。只有共享资源的读写访问才需要同步化。aynchronized是异步锁。
1.5 脏读,synchronized可重入锁,异常线程锁自动释放,同步不具有继承性
发生脏读的情况,就是取值时,实例变量已经被其他线程修改了,加上synchronized方法就可以解决.就是当第一次调用对象锁时,在其内部在次调用,是可以再次获取锁的,虽然第一次的锁没有解开。不然会造成死锁问题
1.6同步代码块
同步代码块,当一个线程正在访问一个Object中的同步代码块时候,另外一个线程可以访问Object中非同步的代码块,可以一半异步,一半同步·,当线程访问一个Object同步代码块时,将停止访问这个object类中的另外一个同步代码块

package threadMainTest;

public class ObjectService {
	public void serviceMethodA() {
		synchronized(this) {
			System.out.println("A start time is " + System.currentTimeMillis());
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println("A end time is " + System.currentTimeMillis());
		}
	}
	
public void serviceMethodB() {
	synchronized(this) {
		System.out.println("B start time is " + System.currentTimeMillis());
		System.out.println("B end time is " + System.currentTimeMillis());
	}
}

}

package threadMainTest;

import org.omg.PortableInterceptor.ObjectReferenceTemplateSeqHolder;

public class ThreadA extends Thread {
	private ObjectService objectService;

public ThreadA(ObjectService objectService) {
	super();
	this.objectService = objectService;
}

@Override
public void run() {
	// TODO Auto-generated method stub
	super.run();
	objectService.serviceMethodA();
}

}

    package threadMainTest;
    
    import org.omg.PortableInterceptor.ObjectReferenceTemplateSeqHolder;
    
    public class ThreadB extends Thread {
    	private ObjectService objectService;
	
	public ThreadB(ObjectService objectService) {
		super();
		this.objectService = objectService;
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.run();
		objectService.serviceMethodB();
	}
}

package threadMainTest;

public class Run2 {
	public static void main(String[] args) throws InterruptedException {
		ObjectService objectService = new ObjectService();
		ThreadA threadA = new ThreadA(objectService);
		threadA.start();
		//Thread.sleep(200);
		ThreadB threadB = new ThreadB(objectService);
		threadB.start();
	}
}

运行结果:
A start time is 1543307979305
A end time is 1543307981313
B start time is 1543307981313
B end time is 1543307981313
注:当多个线程调用同一个对象中的Synchroinzed同步方法或Synchroized(this)同步代码块的时,调用的效果是安顺序执行,也就是同步的,阻塞的。
1.7 静态同步Synchronized
当synchronized加到Static方法上,是给Class类上锁,加到非Static方法上,是给对象上锁。String常量池对Synchronized的影响。

package threadMainTest;

public class ObjectService {
	public static void print(String username) {
		synchronized (username) {
			while(true) {
				System.out.println(Thread.currentThread().getName());
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			
		}
	}
}
package threadMainTest;

import org.omg.PortableInterceptor.ObjectReferenceTemplateSeqHolder;

public class ThreadA extends Thread {
	private ObjectService objectService;
	
	public ThreadA(ObjectService objectService) {
		super();
		this.objectService = objectService;
	}
	
	@Override
	public void run() {
		objectService.print("AA");
	}
}
package threadMainTest;

import org.omg.PortableInterceptor.ObjectReferenceTemplateSeqHolder;

public class ThreadB extends Thread {
	private ObjectService objectService;
	
	public ThreadB(ObjectService objectService) {
		super();
		this.objectService = objectService;
	}
	
	@Override
	public void run() {
		objectService.print("AA");
	}
}
package threadMainTest;

public class Run2 {
	public static void main(String[] args) throws InterruptedException {
		ObjectService objectService = new ObjectService();
		ThreadA threadA = new ThreadA(objectService);
		threadA.setName("A");
		threadA.start();
		//Thread.sleep(200);
		ThreadB threadB = new ThreadB(objectService);
		threadB.setName("B");
		threadB.start();
	}
}

 结果展示
A
A
A
A
A
A
A
A
A
A
A
因为两个线程都是里面的输入字符都是AA,所以会导致,两个线程拿到的锁都是相同的,所以会造成B阻塞.这是String常量池引起的,这种情况,可以把变量改为Object类型,这样就不是一个锁了,因为new Objectr()不在缓存里面。所以第二次会new 一个新的对象。
1.8 死锁就是双方互相持有对方锁的情况,比如A执行需要用到B对象,但是B执行也需要用到A对象。同时需要,则会造成死锁,切记,死锁和死循环是两种不同的情况,死循环是不断地重复,死锁是等待对方释放资源。
2. Volatile关键字
Volatile变量增加了实例变量在多个线程的可见性。但volatile关键字最致命的是不支持原子性,volatile只能修饰变量,synchronized可以保证原子性,也可以间接保证可见性,因为它会将私有内存和公共内存中的数据做同步。
package thread;

public class HaselfPrivateNum extends Thread{
volatile public static int num ;

@Override
public void run() {
	for (int i = 0; i < 100; i++) {
		num++;
	}
	System.out.println("num = " + num);
}

}

package thread;

public class Run {

public static void main(String[] args) {
	HaselfPrivateNum []haselfPrivateNum = new HaselfPrivateNum[100];
	for (int i = 0; i < 100; i++) {
		haselfPrivateNum[i] = new HaselfPrivateNum();
	}
	for (int i = 0; i < 100; i++) {
		 haselfPrivateNum[i].start();
	}
}

}
结果展示:
num = 3600
num = 3900
num = 4000
num = 4100
num = 4200
num = 4300
num = 4400
num = 4500
num = 4600
 增加了线程之间的可见性,但是不具备同步性!关键字valitile保证了线程每次从共享内存中读取数据,而不是从私有内存中读取数据,这样保证了同步数据的可见性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值