您的位置:首页 > 编程语言 > Java开发

Java多线程基础

2010-11-06 13:36 671 查看
一、线程基本介绍

1.线程和进程的区别

(1)进程是系统进行资源分配和调度的一个独立单位

(2)线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位

(3)进程有独立的地址空间

(4)同一个进程中的线程没有独立的地址空间,它们共享地址空间;线程也有自己的堆栈和局部变量

2.线程创建方法

(1)继承Thread类,实现run方法

class MyThread extends Thread {
…
public void run() {
//do something
}
…
}
MyThread runThread = new MyThread();
runThread.start();


(2)实现runnable接口,并用其初始化Thread对象

Runnable runnable = new Runnable() {
public void run() {
//do something
}
};
Thread runThread = new Thread(runnable);
runThread.start();


3.Thread的主要方法

(1)run

(2)start:线程开始运行

(3)join:调用线程执行x.join(),表示调用线程等待x线程执行完

(4)sleep:当前线程休眠

(5)yield:当前线程出让CPU

(6)isInterrupted:是否处于中断状态

(7)interrupt:设置线程的中断状态

(8)interrupted:清除线程的中断状态

(9)setDeamon:设置是否守护线程

(10)setPriority:设置优先级

4.ThreadLocal类

存放对应于线程的相关对象,每个线程只能存取本线程的ThreadLocal中的对象

ThreadLocal类实现:

1)以Thread为key,得到的value为一个类似于Map的结构

2)在这个Map中,以ThreadLocal对象为key,得到这个ThreadLocal对象相应的value,即为相应的值

使用实例:

class ConnectionManager {
private static final ThreadLocal<Connection> connStore = new ThreadLocal<Connection>();
public static Connection getConnection() {
return connStore.get();
}
public static void setConnection(Connection conn) {
If (conn != null) {
connStore.set(conn);
} else {
connStore.set(null);
}
}
}


Servlet是多线程的

在执行service方法时,不同线程使用同一个连接会有问题,应使每一个线程得到一个不同的Connection

可以通过filter来实现这个,filter中伪代码如下:

1)从连接池中得到连接conn

2)ConnectionManager.setConnection(conn);

3)chain.doFilter(req, resp);

4)ConnectionManager.setConnection(null);

5)将连接返回连接池

6)在servlet中可以通过ConnectionManager.getConnection()来得到连接,从而执行数据库操作

5.Timer和TimerTask类

用于定时性任务的触发

用于周期性任务的触发

schedule:“fixed-delay”;如果第一次执行被delay了,随后的执行按照execution-time计算,也会被delay

scheduleAtFixedRate:“fixed-rate”;如果第一个执行被delay了,随后的执行按照initial-time计算,基本不会被delay

二、线程状态

对应于Thread.State枚举



三、线程安全

(1)类的线程安全性:如果一个类在多线程的访问下,其状态是可以预测的,并且不需要额外的同步,那么这个类就是线程安全的类

(2)封装:封装限制了代码路径,使得线程安全更有可能

(3)组合:非线程安全类-->线程安全类;线程安全类-->非线程安全类

四、synchronized

(1)synchronized是Java的关键字,是线程同步的内部机制,简单、方便,但性能不高

(2)可用于方法声明,方法体内,静态初始化块等;synchronized若用于代码块,加锁的对象可以是普通的Object或XXX.class

(3)synchronized保证了线程的可见性和互斥性

(4)可见性:一个线程的执行结果可以被另一个线程所看到

(5)互斥性:在同一时间只能有一个线程进行被保护的代码块

示例如下:

public class Singleton {
private static Singleton unique = null;
public static synchronized Singleton getInstance() {
if (unique == null) {
unique = new Singleton();
}
return unique;
}
}


五、volatile

(1)volatile是Java的关键字,是线程同步的内部机制

(2)volatile只保证了线程的可见性,未保证互斥性

(3)volatile由于未保证互斥性,因此只适用于部分使用场景

(4)使用volatile的条件

a)对变量的写操作不依赖于当前值(例如:count++)(因其不保证原子性)

b)该变量没有包含在具有其他变量的不变式中(例如:不变式为lower<upper,其中lower,upper为volatile变量)

c)访问该变量时,没有其他原因需要加锁

(5)使用volatile的场景

a)状态标志(ExecutorService)(代码:ServiceProvider)

b)对象的安全发布(Future)(代码:ResultObject)

示例:

(1)volatile状态标志





(2)volatile对象安全发布





六、wait、notify、notifyAll

(1)是Object类的方法

(2)是Java内部的条件阻塞机制

(3)条件阻塞机制的三要素:锁、条件、等待队列

(4)wait使调用线程阻塞,并等待其他线程的唤醒或是中断、超时

(5)notify在等待队列中选择一个线程使之运行(线程饿死)

(6)notifyAll激活等待队列中所有的线程,并且只能有一个线程能运行成功,其余仍等待

(7)逻辑:

synchronized(lock) { //锁

if (xxxxxx) { //条件

lock.wait(); //等待队列

} else {

doLogic();

}

}

synchronized(lock) { //锁

doLogic();

if (xxxxxx) { //条件

lock.notifyAll(); //等待队列

}

}

七、interrupt、interrupted



(1)interrupt设置线程状态为中断状态

(2)interrupted清除线程的中断状态,返回清除前的值

(3)wait,join,sleep以及J.U.C中一些类如ArrayBlockingQueue支持中断,并且在中断时都抛出InterruptedException,并且清除中断状态

(4)要指出的是:不是因为在其他线程中调用了x.interrupt(),x线程执行中就一定会抛出异常;抛出的InterruptedException是因为,wait、sleep等方法在循环中检查了线程状态,当被设置为中断后,就会抛出异常,并清除中断状态

(5)线程InterruptedException的处理方法:

a)简单地抛到调用者,由调用者处理

b)保存中断状态(Thread.currentThread().interrupt()),由上层代码处理(如:线程池中某一线程的任务被用户取消)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: