并发

本文详细介绍了Java线程的基础知识,包括线程状态、属性、同步机制、锁与条件对象的使用,以及高级主题如阻塞队列、线程安全的集合、Callable与Future、执行器和线程池等。深入探讨了线程中断、死锁、volatile变量、原子性和读写锁的概念。

1、使用线程给其他任务提供机会
1)中断线程
interrupt方法可以用来请求终止线程。当对一个线程调用interrupt方法时,线程的中断状态将被置位,这是每个线程都具有的boolean标志。每个线程都应该不时地检查这个标志,以判断线程是否被中断。判断方法:Thread.currentThread().isInterrupted();
注:如果线程被阻塞,就无法检测中断状态。
注:interrupted方法可用于清除该线程的中断状态。
2)线程状态
new(新创建)new时
runnable(可运行)调用start方法时。
blocked(被阻塞)当线程获取不到锁
waiting(等待)当线程等待另一个线程通知调度器一个条件时,自己进入等待状态
timed waiting(计时等待)
terminated(被终止)
现有的操作系统都使用抢占式调度,系统给每个可运行线程一个时间片执行任务,时间片用完,操作系统剥夺该线程运行权,选择下一个线程时,操作系统会考虑优先级。

在这里插入图片描述
3)线程属性

  1. 线程优先级
    可以用setPriority方法设置线程优先级,可设置MIN_PRIORITY(1)~MAX_PRIORITY(10)之间

  2. 守护线程
    通过调用setDaemon(true)将线程转化为守护线程。守护线程的唯一用处:为其他线程提供服务。只剩守护线程时,虚拟机就退出了。守护线程不应该访问固有资源,如文件,数据库,因为守护线程会在任何时候中断。

2、同步
两个或以上线程共享对同一数据的读取
1)锁对象
例:使用ReentrantLock保护代码块
mylock.lock();
try{

}finally{
mylock.unlock();//防止临界区代码抛出异常导致其他线程永远被阻塞
}
锁是可重入的,线程可以重复的获得已经持有的锁
2)条件对象
以转账为例
public void transfer(int from,int to,int amount){
banklock.lock();
try{
while(account[from]<amount){
//钱不够等待
}
//转账
}finally{
banklock.unlock();
}
}
账户余额不够时,线程已获得锁,且在等待,其他线程无法给此账户转账。
可给被锁对象设置条件对象,如在Bank类中,private Condition sufficient;sufficient=banklock.newCondition();
余额不足时,调用sufficient.await();线程阻塞且放弃锁,其他线程可对账户进行操作。其他线程操作完成后,调用signalAll()重新激活因此条件而等待的所有线程。被激活的线程会从被阻塞的地方继续执行。此时原线程中的执行条件可能仍不满足,因此要这样写:
while(!执行条件){
condition.await();
}
3)synchronized关键字
Java中每个对象都有一个内部锁。如果一个方法用synchronized申明,则对象的锁会保护整给方法。内部对象锁只有一个相关条件。wait方法添加一个线程到等待集中,notify/notifyAll解除等待线程的阻塞状态。
例:

class Bank{
	private double[] accounts;
	public synchronized void transfer(int from,int to,int amount){
		while(accounts[from]<amount){
			wait();
		}
		accounts[from]-=amount;
		accounts[to]+=amount;
		notifyAll();
	}
}

也可将静态方法申明为synchronized。调用该方法时,获得相关的类对象的内部锁,类名.class被锁住。
4)监视器
1.监视器是只包含私有域的类
2.每个监视器类的对象有一个相关的锁
3.使用该锁对所有的方法进行加锁。即如果调用obj.method(),obj对象的锁在方法调用开始时自动获得,方法返回时自动释放。
4.该锁可以有任意多个相关条件
5)volatile域
volatile关键字为实例域的同步访问提供了一种免锁机制。如果申明一个域为volatile,那么编译器和虚拟机就知道该域是可能被另一个线程并发更新的。volatile 关键字可以保证变量会直接从主存读取,而对变量的更新也会直接写到主存。防止一个线程更改变量,变量还未写入主存时,其他线程访问变量,得到原来的值的错误情况。
注:volatile变量不能提供原子性。
7)原子性
java.util.concurrent.atomic包中有很多类使用了很高效的机器级指令来保证操作原子性。
例:AtomicInteger类提供incrementAndGet()与decrementAndGet()
8)死锁
9)线程局部变量
ThreanLocal类为各个线程提供各自的实例。
例:public static final ThreadLocal<SimpleDateFormat> dateFormat=ThreadLocal.withinitial(()->new SimpledateFormat(“yyyy-MM-dd”));
使用时:String dateStamp = dateFormat.get().format(new Date());线程首次调用get时,会调用initialValue方法,之后get会返回属于当前线程的实例。
10)锁测试与超时
线程尝试获取另一个线程所持有的锁时,可能发生阻塞。可使用tryLock尝试申请
11)读锁与写锁
private ReentrantReadWriteLock rwl=new ReentrantReadWriteLock();
private Lock readLock=rwl.readLock();
private Lock writeLock=rwl.writeLock();
3、阻塞队列
使用队列解决线程安全问题,线程将指令插如一个队列中,另一个线程负责从队列取出指令执行,只有该线程能访问对象。当队列已满。仍要加入指令或队列为空,仍要取出指令时,阻塞队列导致线程阻塞。
在这里插入图片描述
阻塞队列的一些变种:LinkedBlockingQueue、ArrayBlockingQueue、PriorityBlockingQueue

4、线程安全的集合
1)高效的映射、集和队列
ConcurrentHashMap 可被多线程安全访问的散列映射表
ConcurrentSkipMap 可被多线程安全访问的有序映像表
ConcurrentSkipListSet 可被多线程安全访问的有序集
ConcurrentLinkedQueue 可被多线程安全访问的无边界非阻塞的队列
2)映射条目的原子更新
compute方法,接收键和相关联的值。
例:map.compute(word,(k,v)->v==null?1:v+1);
5、Callable与Future
Callable与Runnable类似,但是有返回值

public interface Callable<V>{
	V call() throws Exception
}

Future保存异步计算的结果。可以启动一个计算,将Future对象交给某个线程,Future对象的所有者在结果计算好后就可以获得他。

public interface Future<V>{
	V get()throws...;
	V get(long timeout,TimeUnit unit) throws;...
	void cancel(boolean mayInterrupt);
	boolean isCancelled();
	boolean isDone();
}

第一个get方法的调用被阻塞,计算完成时返回。
FutureTask包装器是一种非常便利的机制,可将Callable转换成Future和Runnable,它是同时实现二者的接口
例:
Callable<Integer> call=…;
FutureTask<Integer> task=new FutureTask<Integer>(call);
Thread t =new Thread(task);//Runnable
t.start();

Integer result=task.get();//Future
6、执行器
执行器类有许多静态工厂方法用来构建线程池
1)线程池
使用线程池时应做的事;

  1. 调用Executors类中的静态方法newCachedThreadPool或newFixedThreadPool
  2. 调用submit提交Runnable或Callable对象,返回Future对象
  3. 如果想取消一个任务,或如果提交Callable对象,那就要保存好返回的Future对象
  4. 不再提交任务时,调用shutdown
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值