多线程

来源:互联网 发布:走路赚钱的软件 编辑:程序博客网 时间:2024/05/16 08:05

一、进程和线程的概念

在操作系统中,每个运行的程序就是一个进程,进程可以执行多个任务,每个任务就是一个线程。

进程在执行过程中拥有自己独立的内存单元,而多个线程共享内存。

进程之间不能共享内存,但线程实现共享内存很容易。

系统创建进程时要为其分配系统资源,而创建线程代价小的多。

二、多线程的创建和启动

1.继承Thread类

2.实现Runnable接口

3.实现Callable接口,重写call方法,然后用FutureTask封装,call方法可以有返回值,可以声明抛出异常。

三种方式的比较

实现Runnable接口和Callable接口的方式:线程只是实现了接口,还可以继承其他类;在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一资源的情况;劣势是要访问当前线程要用Thread.currentThread()

采用Thread方法就不能继承其他类,如果要访问当前线程可以直接用this访问

三、线程的生命周期

新建、就绪、运行、阻塞、死亡

四、控制线程

1.join():让一个线程等待另一个线程执行完成的方法,调用线程将被阻塞,直到被join()加入的join线程执行完为止

2.后台线程:在后台运行的线程,如果前台线程都死亡,则后台线程自动死亡。Thread.setDaemon(true)

3.线程睡眠sleep(long millis),让当前正在执行的线程暂停millis毫秒,并进入阻塞状态

4.线程让步yield(),让当前正在执行的线程暂停,进入就绪状态,只有优先级相同或更高的处于就绪状态的线程才会获得机会执行


5.sleep方法和yield方法比较:

sleep方法暂停当前线程后,会给其他线程执行机会,不会考虑优先级,但yield只会给优先级相同或更高的线程执行机会;

sleep方法会将线程转入阻塞状态,直到经过阻塞时间才会变成就绪状态,而yield方法会将线程进入就绪状态;

sleep方法声明抛出InterruptedException异常,所以调用sleep方法时,要么捕捉异常要么声明抛出该异常,而yield方法则没有抛出任何异常;

sleep方法比yield方法有更好的移植性,通常不建议使用yield方法来控制并发线程的执行。

6.线程的优先级

Thread.setPriority(int newPriority);

newPriority可以是1~10的数字,也可以是Thread类的3个静态常量:MAX_PRIORITY(10),MIN_PRIORITY(1),NORM_PRIORITY(5)

五、线程同步

使用同步代码块:将要同步的代码用synchronized{}包含起来

同步方法:用synchronized修饰某个方法

同步锁Lock:定义一个锁对象(可重入锁) private final ReentrantLock lock = new ReentrantLock(); 加锁:lock.lock();  释放锁:lock.unlock();

六、线程通信

1.传统的线程通信

可以使用Object类的wait(),notify(),notifyAll()

wait():导致当前线程等待,直到其他线程调用该同步监视器的notify()或notifyAll()来唤醒该线程。wait方法有三种形式:无时间参数的wait(一直等待,直到其他线程通知),

带毫秒参数的wait和带毫微秒参数的wait(这两种方法都是等待指定时间后自动苏醒)。调用wait方法的线程会释放对同步监视器的锁定。

notify():唤醒在此同步监视器上等待的单个线程,选择是任意的,只有当前线程放弃对该同步监视器的锁定后(使用wait方法),才可以执行被唤醒的线程。

notifyAll():唤醒在此同步监视器上等待的所有线程

死锁是两个线程等待对方释放同步监视器,阻塞是等待其他线程唤醒线程,不等待其他线程释放同步监视器

2.使用Condition控制线程通信

如果程序不使用Synchronized关键字来保证同步,而是直接使用Lock对象来保证同步,则系统中不存在隐士的同步监视器,也就不能使用wait(),notify(),notifyAll()方法进行线程通信。

当使用Lock对象来保证同步时,java提供了一个Condition类来保持协调。Condition将同步监视器方法分成截然不同的对象,Lock替代了同步方法或同步代码块,Condition替代了同步监视器。

Condition实例被绑定在一个Lock对象上,要获得特定lock实例的Condition对象,调用Lock对象的newCondition()方法即可。Condition提供了如下三个方法:

await():类似于隐式同步监视器的wait(),导致当前线程等待,直到其他线程调用该线程的signal()方法或signalAll()方法来唤醒该线程。该await方法有更多变体,如long awaitNanos(long nanosTimeout),void awaitUninterruptibly(),awaitUtil(Date deadline)等。

signal():唤醒在此Lock对象上等待的单个线程

signalAll():唤醒在此lock对象上等待的所有线程

3.使用阻塞队列(BlockingQueue)控制线程通信

Java5提供了一个BlockingQueue接口,是queue的子接口,但它主要用途不是作为容器,而是作为线程同步的工具。

在队列尾部插入元素:add(E e),offer(E e),put(E e),当该队列已满时,这3个方法分别会抛出异常,返回false,阻塞队列。

在队列头部删除并返回删除的元素:remove(),poll(),take(),当该队列已空时,这3个方法分别会抛出异常,返回false,阻塞队列。

在队列头部取出但不删除元素:element(),peek(),当队列已空时,这两个方法分别抛出异常,返回false。





0 0
原创粉丝点击