线程同步

本文介绍了在多线程环境下,如何使用Java的synchronized关键字实现线程同步,确保原子操作,避免数据不一致问题。通过示例展示了加锁解锁的原理,并提出了使用封装的同步方法和Read-Write Lock来提高并发性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多个线程同时读写共享变量时,会出现数据不一致的问题。这时就需要解决线程同步的问题。

public class Main{
	public static void main(String[] args) throws Exception{
	var add=new AddTread();
	var add=new DecThread();
	add.start();
	dec.start();
	add.join();
	dec.join();
	System.out.println(Counter.count);
}
}
class Counter{
 public static int count=0;
}
class AddThread extends Thread{
	public void run(){
	for(int i=0;i<1000;i++){
	Counter.count+=1;}}
}
class DecThread extends Thread{
	public void run(){
	for(int i=0;i<1000;i++){
	Counter.count-=1}}
}
两个线程同时对一个共享变量进行操作,一个加1000次,一个减1000次。在不加锁的情况下,结果不为0;要保证结果正确,必须让操作是原子操作,原子操作是指不能被中断的一个或者一系列操作。即当一个线程进行加操作的时候,另一个必须等待,等加操作完成之后在进行减操作。

加锁和解锁

保证一段代码的原子性就是通过加锁和解锁实现。Java程序使用synchronized关键字对一个对象进行加锁

sysnchronized(lock){
n=n+1;
}
syschronized关键字保证了代码块在任意时刻只能有一个线程能执行,
将上面操作进行加锁之后
public class Main{
	public void static main(String[] args)throws Excetion{
	var add=new AddThread();
	var dec=neww DecThread();
	add.start;
	dec.start;
	add.join();
	dec.join();
	System.out.println(Counter.count)
}
}
class Counter{
	public static final Object lock =new Object();
	public static int count=0;
}
class AddThread extends Thread{
	public void run(){
	for(int i=0;i<1000;i++){
		syschronized(Counter.lock){
		Counter.count+=1;}
}}
}
class DecThread extends Thread{
	public void run(){
	for(int i=0;i<1000;i++){
		syschronized(Counter.lock){//获取锁
		Counter.count+=1;}//释放锁 
}
}
}
在获取锁和释放锁之间的代码块为原子操作。

不需要syschronized的操作

JVM定义了几种原子操作:
基本类型:int n=m
引用类型赋值,Listlist=anotherList

正确的同步方法

在进行加锁的时候,更好的办法是将加锁方法封装起来。

public class Mian{
	public static void main(String[] args){
	var c1=Counter();
	var c2=Counter();
	// 对c1进行操作的线程:
new Thread(() -> {
    c1.add();
}).start();
new Thread(() -> {
    c1.dec();
}).start();

// 对c2进行操作的线程:
new Thread(() -> {
    c2.add();
}).start();
new Thread(() -> {
    c2.dec();
}).start();
	}
}
public class Counter{
	private int count=0;
	public void add(int n){
		syschronized(this){//获取锁,锁住的是自己对象,当调用add方法的时候,就会自动获取当前对象的锁。
		count+=n}//释放锁
}
public void dec(int n){
	syschronize(this){//获取当前对象锁
	count+=1;}//释放当前对象锁
}
public int get(){
return count;}
}

ReadWriteLock

这种锁允许多个线程同时读,当只要有一个线程在写,其他线程就必须等待。
只允许一个线程写入(其他线程既不能读,也不能写)。
没有写入时,多个线程可以同时读(提高性能)

public class Counter{
	private final ReadWriteLock rwlock=new ReentrantReadWriteLock();
	private final Lock rlock=rwlock.readLock();
	private final Lock wlock =rwlock.writeLock();
	private int[] counts=new int[10];
	
	public void inc(int index){
	wlock.lock();//加写锁
	try{
		counts[index]+=1;
}finally{
wlock.unlock();//释放写锁
}
	}
	public int[] get(){
	rlock.lock();//加读锁
	try{
	return Arrays.copyOf(counts,counts.length);}
	finally{
	rlock.unlock();//释放读锁}
	}
}

参考廖雪峰教程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值