概念:多线程在较低的层次上扩展了多任务的概念:一个程序同时执行多个任务。通常,每一个任务成为一个线程,他是线程控制的简称。可以同时运行一个线程以上的程序叫多线程程序。

线程和进程的区别:本质区别在于每个进程有自己独立的变量,而线程共享变量。与进程相比,线程更“轻量级”,创建撤销一个线程比启动新进程的开销小很多。

  • 什么时候使用线程?

  执行一个比较耗时的操作,应使用独立的线程。

  • 在一个单独的线程中执行一个任务的简单过程:
  1. 将任务代码写在实现了Runnable接口的类的run方法里。
  2. 创建一个类对象
  3.  由Runnable创建一个Thread类对象。
  4. 执行start()方法,启动线程。

注意:启动线程时,不要调用Thread类或Runnable接口的run方法。因为直接调用run方法,只会执行同一个线程中的任务,而不会启动线程。应该调用Thread.start方法。这个方法将创建一个执行run方法的新线程。

  • 如何控制线程之间的交互?

通过锁来实现线程之间的交互。在javase 5.0后 ,多线程发生了重大变化,引入大量的类和接口。

锁对象。ReentrantLock和Lock。在java.util.current包中

例子:mylock.lock(){

try{

临界区;

}

finally{

mylock.unlock();

}

 

这一结构确保任何时刻只有一个线程进入临界区。锁是可重入的。那么什么叫可重入的呢?线程可以重复的获得已有的锁。锁保持一个持有计数器来跟踪对lock方法的调用。

条件对象


条件对象出现的原因。想像这样一种情况,我们进入临界区后,发现在满足某一条件后他才能执行。这是我们就需要引入一个条件对象。

线程进入阻塞状态,需要等待某一条件得到满足才能继续执行。这个唤醒条件的执行需要其他线程来实现。这里会涉及到两个方法,await方法,还有一个signal(signalAll)方法。

wait方法是当某一条件不满足时。线程用来主动让自己进入阻塞状态。signal方法用来唤醒进程的,当一个进程释放该条件后,会随机通知一个线程进入可执行状态(signalAll方法把释放所有需要该条件的线程,让他们都有竞争的条件)

 Condition 类。

synchronzied关键字。

如果一个方法用synchronized 关键字声明,那么对象的锁将保护整个方法。也就是说,要调用该方法,线程必须获得内部的对象锁。

一起使用的方法有wait,notify。调用sychronized 方法时,该方法会获得相关的内部锁。每一个对象有一个内部锁,并且该锁有一个内部条件。由锁来管理那些试图进入sychronized方法的线程,由条件来管理那些调用wait的线程。

内部锁和条件有一些局限:

1、不能中断一个正在试图获取锁的线程。

2、试图获取锁时不能获设定超时。

3、每个锁仅有单一的条件,可能会不够。

volatile关键字:

volatile 关键字的适用场景:

例如:有一个变量 flag;

private flag;

public synchronized boolean getflag(){return flag;}

public synchronzied void setflag(){ flag=true;}

如果另一个线程已经对该对象加锁,那么get 和setf方法可能会阻塞。这时内部锁可能不是一个好的策略。

这时就需要将域声明为volatile.

volatile 关键字为实例域的同步访问提供了一种免锁的机制。

警告:volatile 关键字不能提供原子性。不能保证变量读取,计算和写入的过程不被中断。

final变量

将一个变量声明为final,也可以安全地访问一个共享域。

原子性:

java.util.concurrent.atomic包中的很多类使用了高效的机器级指令来保证其他操作的原子性。

线程局部变量:

有时为了避免使用共享变量,可以使用ThreadLocal辅助类为各个线程提供各自的实例。

用法:例如要构造一个SimpleDateFormat对象。

读写锁:

java.util.concurrent.locks提供了两个锁类,ReentrantLock和ReentrantReadWriteLock类。

使用读写锁的步骤:

1、新建一个ReentrantReadWriteLock类的对象。

private ReentrantReadWriteLock rwl=new ReentrantLock();

 

2、抽取读写锁

private ReadLock rel=rwl.readLock();

private WriteLock wrl=rwl.writeLock();

 

3、对所有的获取方法加读锁。

 

4、 对所有的获取方法加写锁。

线程安全的集合: