多线程——线程同步

参考:http://blog.csdn.net/zhangerqing/article/details/8284609

想必大家都知道线程安全问题:如果一个对象的状态是可变的,并且他有是共享的,可以被多个线程同时方案,则存在线程安全问题。

对于此类问题,解决方法主要有三种:

1. 进制跨线程访问变量

2. 使状态变量为不可变

(前两个方法咱就不考虑了,因为他实际上是放弃 了多线程)


3. 使用同步

    a. 是操作原子性:比如value++就是一个非原子性的操作,他是先取值,再加1,最后再赋值。存在线程安全问题。

    使用java.util.concurrent.atomic包的方法可以保证原子性(atomic是如何保证原子性的有待研究),之后呈上一个线程安全的自增序列算法给大家。

public String nextLastSequence()
		{
			Long value = atomic.getAndIncrement();
			if(value > max)
			{
				for(;;)
				{
					if(atomic.compareAndSet(value+1, min))
					{
						value = atomic.getAndIncrement();
						break;
					}
					else{
						value = atomic.getAndIncrement();
						if(value <= max)
						{
							break;
						}
					}
				}
			}
			
			return Filler(String.valueOf(value));
		}


    b. 加锁——内部锁
    c. 加锁——显示锁
    d. 加锁——重进入和读写锁不太理解
    e. 可见性和过期数据概念

    f. volatile变量概念及使用场景


4. 线程同步的几种实现以及对比

/**
 * 
 */
package com.demo;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Maggie
 *
 */
public class AtomicCounter implements Runnable
{
	private final AtomicInteger count = new AtomicInteger(0);
	int count1 = 0;
	
	ReentrantLock lock = new ReentrantLock();
	
	public void run()
	{
		while(true)
		{
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			/**
			 * 同步方法
			 * 1. 内部锁:synchronized
			 * 	1) 获取锁的线程执行完了代码块,然后线程会释放对锁的真有;
			 * 	2) 线程执行发生异常,此时JVM会让线程自动释放锁。
			 * 但是,缺点:
			 * 	如果这个获取锁的线程由于要等待IO或者其他原因(比如调用sleep方法)被阻塞了,
			 * 但是又没有释放锁,其他线程只能干巴巴的等待,这样是很不好的。
			 * 但是这种情况显示锁:Lock就可以办到,接下来也会介绍Lock
			 */
//			synchronized (this) {
//				System.out.println(Thread.currentThread().getName()
//						+ ":" + count1++);
//			}
			
			/**
			 * 2. 原子操作:atomic
			 * 这里使用atomic保证了计数是原子性操作,但是System.out.println时
			 * 非原子性操作,所以会出现下面这种情况,但是数字肯定是不会重复的
			 * 
			 * Thread-1:1
			 * Thread-2:3
			 * Thread-3:4
			 * Thread-0:2
			 * Thread-1:6
			 * Thread-2:5
			 */
//			System.out.println(Thread.currentThread().getName()
//					+ ":" + count.incrementAndGet());
			
			/**
			 * 3. 显示锁
			 * 相比起synchronized的优缺点
			 * 优点:定时所的等待,可中断锁的等待,公平性,以及实现非块结构的锁
			 * 缺点:复杂,易错,还会存在忘记释放锁的风险。
			 * 
			 * 注意:ReentrantLock lock = new ReentrantLock();应该提前到
			 * 为全局变量,如果放在了这个下面作为局部变量就失去了锁的作用了,会出现下面情况
			 * 
			 * 得到了锁
			 * 得到了锁
			 * Thread-2:0
			 * 释放了锁
			 * Thread-0:1
			 * 释放了锁
			 */
//			ReentrantLock lock = new ReentrantLock(); // 放在这里没用,
			lock.lock();
			try {
				System.out.println("得到了锁");
				System.out.println(Thread.currentThread().getName()
						+ ":" + count1++);
			} finally {
				lock.unlock();
				System.out.println("释放了锁");
			}
			
		}
	}
	
	public static void main(String[] args)
	{
		AtomicCounter counter = new AtomicCounter();
		
		Thread t1 = new Thread(counter);
		Thread t2 = new Thread(counter);
		Thread t3 = new Thread(counter);
		Thread t4 = new Thread(counter);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值