【Java】 多线程|线程池|计时器
(一)、多线程
1、线程创建方式:
(1)继承Thread类
class PrimeThread extends Thread {
long minPrime;
PrimeThread(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
PrimeThread p = new PrimeThread(143);
p.start();
编码简单,但存在单继承的局限性,不能继承其他类,不便于扩展。
重写的Run方法不能返回执行结果。
不适合需要返回执行结果的场景。
(2)实现Runnble接口
class PrimeRun implements Runnable {
long minPrime;
PrimeRun(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
PrimeRun p = new PrimeRun(143);
new Thread(p).start();
线程任务类实现接口,便于扩展,但编程多一层包装对象。
重写的Run方法不能返回执行结果。
不适合需要返回执行结果的场景。
(3)实现Callable接口
class PrimeCallable implements Callable{
long minPrime;
PrimeCallable (long minPrime) {
this.minPrime = minPrime;
}
public V call() throws Exception{
// compute primes larger than minPrime
. . .
return V;
}
}
Callable call = new PrimeCallable(143);
FutureTask target = new FutureTask(call);
new Thread(target ).start();
V result = target.get();
通过实现Callable接口再封装成FutureTask对象来创建任务对象。
线程任务类实现接口,扩展性强,可以在线程执行完毕后通过FutureTask返回执行结果。
编码更加复杂(有点牵强)。
2、线程常用方法
(1)final String getName()
Returns this thread's name.(获取线程名称)
(2)final void setName(String name)
Changes the name of this thread to be equal to the argument name.(设置线程名称)
(3)static Thread currentThread()
Returns a reference to the currently executing thread object.(获取当前线程对象)
没必要为线程设置名称,默认名字即可。
3、线程安全问题
多个线程同事操作同一个共享资源的时候可能出现业务安全问题,称为线程安全问题。
线程同步实现使用加锁,把共享资源上锁,让多线程实现先后依次访问。
(1)同步代码块
synchronized(同步锁对象){操作共享资源的代码}
代码块内容被加锁,代码块执行完毕后自动解锁。
同步锁对象理论上可以是任意唯一对象,但存在每个对象创建都会受与锁对象局限。
实例方法推荐使用this作为锁对象,
静态方法推荐使用字节码(类名.call)作为锁对象。
(2)同步方法
在方法定义时使用synchronized修饰即可。
算是隐式锁对象,将整个方法作为同步代码块。
同步方法默认使用this和类名.call作为锁对象
(3)Lock锁
使用Lock的实现类ReentrantLock创建。
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock();
}
}
}
比synchronized丰富,更加强大。
4、线程通信
通常通过共享一个数据的方式实现,根据数据来决定等待自己或是唤醒别人。
如生产者与消费者模型:生产者线程负责生产数据,消费者线程负责消费生产者生产的数据。
一般要求:生产者线程生产完后唤醒消费者,等待自己,消费者消费完后,唤醒生产者,等待自己。
Object类的等待和唤醒方法:
void wait()
void notify()
void notifyall()
注意:上诉方法应该使用当前同步锁对象进行调用。