实现线程同步的几种方法

  • 在多线程程序中,会出现多个线程抢占一个资源的情况,这时间有可能会造成冲突,也就是一个线程可能还没来得及将更改的 资源保存,另一个线程的更改就开始了。可能造成数据不一致。因此引入多线程同步,也就是说多个线程只能一个对共享的资源进行更改,其他线程不能对数据进行修改。
  • 1.如下一个两个线程对一个银行账户进行存钱的小实例,其中使用synchornized修饰方法实现线程的同步
  • 代码如下:
class bank{
	private int count=100;
	public synchronized void dispit() {
		  count+=10;
	}
	public int getcount() {
		return count;
	}
}
class ThreadCount extends Thread{
	private bank count;
	private JTextArea textarea = new JTextArea();
	public ThreadCount(bank count,JTextArea textarea) {
		this.count = count;
		this.textarea = textarea;
	}
	public void run() {
		for(int i=0; i<10; i++) {
			count.dispit();
			textarea.append("账户余额为:"+count.getcount()+"\n");
		}
	}
}

2.同步是一种高开销的操作,因此应该尽量减少同步内容,因此也可以使用修饰代码块来代替修饰整个方法。

class bank{
	private int count=100;
	public void dispit() {
		synchronized(this) {
		  count+=10;
		}
	}
	public int getcount() {
		return count;
	}
}
class ThreadCount extends Thread{
	private bank count;
	private JTextArea textarea = new JTextArea();
	public ThreadCount(bank count,JTextArea textarea) {
		this.count = count;
		this.textarea = textarea;
	}
	public void run() {
		for(int i=0; i<10; i++) {
			count.dispit();
			textarea.append("账户余额为:"+count.getcount()+"\n");
		}
	}
}

3.使用volatile修饰数据,对于当下问题,只用使用volatile来修饰账户的余额变量即可。该修饰词是对域变量的访问提供了以这种防锁机制,相当于告诉虚拟机,该域的变量可能被更改。因此每次使用该域都要重新计算,而不是从寄存器中取出数据。从而实现线程的同步。该修饰词不能修改final类型变量

class bank{
	private volatile int count=100;
	public void dispit() {
		  count+=10;
	}
	public int getcount() {
		return count;
	}
}
class ThreadCount extends Thread{
	private bank count;
	private JTextArea textarea = new JTextArea();
	public ThreadCount(bank count,JTextArea textarea) {
		this.count = count;
		this.textarea = textarea;
	}
	public void run() {
		for(int i=0; i<10; i++) {
			count.dispit();
			textarea.append("账户余额为:"+count.getcount()+"\n");
		}
	}
}

4.使用重入锁实现线程同步。使用类ReentrantLock类来定义锁,其中lock()方法为打开锁,unlock()方法为关闭锁
类似于synchronized修饰方法有一样功能。使用锁时间需要注意应该及时放开锁,不然会进入死锁状态。一般是在finally中释放锁

class bank{
	private volatile int count=100;
	private Lock lock = new ReentrantLock();
	public void dispit() {
		 lock.lock();
		 try {
		  count+=10;
		 }finally{
			 lock.unlock();
		 }
	}
	public int getcount() {
		return count;
	}
}
class ThreadCount extends Thread{
	private bank count;
	private JTextArea textarea = new JTextArea();
	public ThreadCount(bank count,JTextArea textarea) {
		this.count = count;
		this.textarea = textarea;
	}
	public void run() {
		for(int i=0; i<10; i++) {
			count.dispit();
			textarea.append("账户余额为:"+count.getcount()+"\n");
		}
	}
}

代码的输出结果如下:
实现线程同步的几种方法_第1张图片
可以看到,每次增加10 的时间只有一个线程在进行,也就是线程的同步

5.使用ThreadLocal类来管理。不过该方法和同步机制不相同。该类管理的变量在每个线程中都有自己的副本,副本之间相互独立,因此获得的结果和其他不同。

class bank{
	private static ThreadLocal count = new ThreadLocal() {
	   protected Integer initialValue() {
		   return 100;
	   }
	};
	private Lock lock = new ReentrantLock();
	public void dispit() {
		 lock.lock();
		 try {
		  count.set(count.get()+10);
		 }finally{
			 lock.unlock();
		 }
	}
	public int getcount() {
		return count.get();
	}
}

class ThreadCount extends Thread{
	private bank count;
	private JTextArea textarea = new JTextArea();
	public ThreadCount(bank count,JTextArea textarea) {
		this.count = count;
		this.textarea = textarea;
	}
	public void run() {
		for(int i=0; i<10; i++) {
			count.dispit();
			textarea.append("账户余额为:"+count.getcount()+"\n");
		}
	}
}

结果如图:
实现线程同步的几种方法_第2张图片
可以看到,在改程序中,好比两个账户相互独立,互不干扰一样。同样解决了相同的变量访问冲突问题。

你可能感兴趣的:(java,实战)