多线程
Java内部支持多线程,即一个程序种运行多个任务。
线程: 一个程序可能包含多个并发执行的任务。线程是一个任务从头到尾的执行流。在java中每个任务都是runnable接口的一个实例,也称为可运行对象(runnable object)。线程本质上讲就是便于任务执行的对象。
任务就是对象。任务中的run()方法指明如何完成任务。Java虚拟机会自动调用该方法,无需特意调用它。直接调用run()只是在同一个线程中执行该方法,而没有新线程被启动。
Thread类:包含为任务而创建的线程的构造方法,以及控制线程的方法。
可以通过给thread 变量赋值null来表明它被停止。
可以通过yield()为其他线程临时让出cpu时间。
Sleep方法可能会抛出一个InterruptedException,这是一个必检异常。当一个休眠线程的interrupt()方法被调用时,就会发生一个这样的异常。循环要在try-catch块外,要不然线程即使被中断,也有可能继续执行。
可以使用join()方法使一个线程等待另一个线程的结束。
Java给每一个线程指定一个优先级,java虚拟机总是选择当前优先级最高的可运行线程。
线程池:它是管理并发执行任务个数的理想方法Executor接口来执行线程池中的任务,ExecutorService是Executor的子接口,用来管理和控制任务。
线程同步:为了避免共享资源被多个线程同时访问时,遭到破坏。多线程中引起冲突的方式访问公共资源,称为竞争状态(race condition)。如果一个类的对象在多线程中没有导致竞争状态,则称为线程安全的(thread - safe)。
Synchronized同步:共享资源部分称为临界区(criticalregion)。可以使用关键字synchronized来同步方法,以便只有一个线程可以访问这个方法。
一个同步方法在执行前需要加锁。对于实例方法,要给调用该方法的对象加锁。对于静态方法,要给这个类加锁。
同步语句:同步语句允许设置同步方法中的部分代码,而不必时整个方法。这大大增强了程序的并发能力。同步语句不仅可以对于this对象加锁,还可以对任何对象加锁,任何同步的实例方法都可以转换成同步语句。
加锁同步:synchronized同步的实例方法在执行之前都隐式的需要一个锁,java可以显示加锁,这增加了更多的控制功能。一个锁是一个Lock接口的实例,它定义了加锁和解锁的方法。锁也可以使用newCondition()方法来创建任意个数的Conditon对象,用来进行线程间通信。ReentrantLock是为创建相互排斥的锁的Lock的具体实现。
线程间协作:线程同步可以避免竞争状态的发生,但是有时候还需要线程之间的相互协作。
阻塞队列(blockingqueue):在试图向一个满队列添加元素或者从空队列中删除元素时会导致线程阻塞。使用锁和条件同步生产者和消费者的线程的方法可以用阻赛队列实现,因为它们内部已经在内部实现。
信号量(semaphore):信号量可以用来限制访问共享资源的线程数。在访问资源之前,线程必须从信号量获取许可。在访问资源之后,这个线程必须将许可以返回给信号量。闯将信号量时,必须选择公平策略来确定许可的数量。只有一个许可信号量可以用来模拟一个互相排斥的锁。
死锁(deadlock):两个或者多个线程需要在几个共享对象上获取锁时,可能会导致死锁。每个线程已经锁定一个对象,而且正在等待锁定另一个对象。可以使用资源排序(resource ordering)的简单jishu 可以轻易避免死锁的发生,也就时每一个需要锁的对象指定一个顺序,确保每个线程按照顺序来获取锁。
线程的状态:新建、就绪、运行、阻塞或者结束。
同步集合:Java集合框架中的类不是线程安全的,也就是说他们同时被多个线程访问和更新,内容会遭到破坏。Collections 类提供六个静态方法来将集合转成同步版本。使用这些方法创建的集合称为包装类(synchronization wrapper)。
Vector、Stack和HashTable是java中的旧类,他们都是同步的。应该用ArrayList替换vector、LinkedList替换Stack和Map代替HashTable。如果要使用同步就是用包装类。
这些包装类是线程安全的,但是迭代器具有快速失败(fail-fast)的特性。这就意味着当下层集合被另一个线程修改时。如果在整个集合中使用一个迭代器,那么迭代器就会抛出异常而结束。这时,需要创建一个同步集合对象。并且遍历时获取对象上的锁。
搞个例子:
// A thread for adding a penny to the account
private static class AddAPennyTask implements Runnable {
public void run() {
// synchronized(this) {
account.deposit(1);
// } /对AddAPennyTask加锁没有效果 必须对account加锁
}
}
// An inner class for account
private static class Account {
private int balance = 0;
public int getBalance() {
return balance;
}
public void deposit(int amount) {
//synchronized(this) {
int newBalance = balance + amount;
// This delay is deliberately added to magnify the
// data-corruption problem and make it easy to see.
try {
Thread.sleep(5);
}
catch (InterruptedException ex) {
}
balance = newBalance;
}
//}
}