java线程方法很多,此文章并不一一列出,下面是我在运用java多线程的编码过程中,用到的几个知识点。
多进程和多线程的本质区别:每个进程拥有自己的一整套变量,而线程则共享数据,在一些操作系统中,线程更“轻量级”,创建、撤销一个线程比启动新进程的开销要小得多
1.线程的基本概念
1.1方法:java.lang.Thread
static void sleep(long millis) 休眠给定的毫秒数
例子:
for(int i=1; i <= ***, i++){
Tread.sleep(1);
}
1.2
下面是在一个单独的线程中执行一个任务的简单过程:
a.将任务代码移到实现了Runnable接口的类的run方法中。这个接口非常简单,只有一个方法“
public interface Runnable{
void run();
}
可以如下所示实现一个类:
class MyRunnable implements Runnable{
public void run(){
//task code
}
}
b.创建一个类对象:Runnable r = new MyRunnable();
c.由Runnable创建一个Thread对象:Thread r = new Thread(r);
d.启动线程: t.start(); //注意:不要调用Runnable对象的run()方法。直接调用run方法,只会执行同一个线程中的任务,而不会启动新线程。
1.3 中断线程
import java.lang.Thread
-
- void interrupt()// 向线程发送中断请求。线程的中断状态将被设置为true。如果目前该线程被一个sleep调用阻塞,那么,InterruptedException异常被抛出
- static bollean interrupted() //测试当前线程(即正在执行这一命令的线程)是否被中断。注意,这是一个静态方法,这一调用会产生副作用—它将当前线程的中断状态重置为false
- boolean isInterrupted() //测试线程是否被终止,不像静态的中断方法,这一调用不改变线程的中断状态
- static Thread currentThread //返回代表当前执行线程的Thread对象
2.同步:
2.1锁对象
用ReentrantLock保护代码块的基本结构如下:这一结构确保任何时刻只有一个线程进入临界区。一旦一个线程封锁了锁对象,其他任何线程都无法通过lock语句。当其他线程调用lock时,他们被阻塞,知道第一个线程释放锁对象。
Lock myLock = new ReentrantLock();
myLock.lock();
try{
//critical section
}
finally{
myLock.unlock();
}
锁时可重入的,因为线程可以重复地获得已经持有的锁。
2.2 条件对象
通常,线程进入临界区,却发现在某一条件满足之后才能执行,要使用条件对象来管理那些已经获得了一个锁但是却不能做有用工作的线程。
一个锁对象可以有一个或多个相关的条件对象。
import java.util.concurrent.locks.Lock
-
- Condition newCondition()//返回一个与该锁相关的条件对象
import java.util.concurrent.locks.Condition
-
- void await()//将该线程放到条件的等待集中
- void signalAll() //解除该条件的等待集中的所有线程的阻塞状态
- void signal() //从该条件的等待集中随机地选择一个线程,解除其阻塞状态
小结:
锁Lock和条件Condition的关键之处
(1)锁用来保护代码片段,任何时刻只能有一个线程执行被保护的代码
(2)锁可以管理试图进入被保护代码段的线程
(3)锁可以拥有一个或多个相关的条件对象
(4)每个条件对象管理那些已经进入被保护的代码段但还不能运行的线程
2.2 synchronized关键字
从1.0版开始,java中的每一个对象都有一个内部锁。如果一个方法用synchronized关键字声明,那么对象的锁将保护整个方法。即要调用该方法,线程必须获得内部的对象锁
即: public synchronized void method(){
//method body
}
等价于
public void method(){
this.intrinsicLock.lock();
try{
//method body
}
finally{this.intrinsicLock.unlock();}
}
内部锁和条件存在一些局限:(1)不能中断一个正在试图获得锁的线程
(2)试图获得锁时不能设定超时
(3)每个锁仅有单一的条件,可能是不够的
小结:在代码中应该使用哪一种?Lock和Condition对象还是同步方法?下面是一些建议:
-
- 最好即不使用Lock/Condition也不使用synchronized关键字。在许多情况下可以使用java.util.concurrent包中的一种机制,它会为你处理所有的加锁。
- 如果synchronized关键字适合你的程序,那么请尽量使用它,这样可以减少编写的代码数量,减少出错的几率。
- 如果特别需要Lock/Condition结构提供的独有特性是,才使用Lock/Condition。
2.3 读/写锁
java.util.concurrent.locks包定义了两个锁类:ReentrantLock类和ReentrantReadWriteLock类。如果很多线程从一个数据结构读取数据而很少线程修改其中的数据的话,后者十分有用。在这种情况下,允许对读者进行线程共享访问是合适的。当然,写着线程依然必须是互斥访问的
下面是使用读/写锁的必要步骤:
1)构造一个ReentrantReadWriteLock对象:
private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
2) 抽取读锁和写锁:
private Lock readLock = rwl.readLock(); //得到一个可以被多个读操作公用的读锁,但会排斥所有写操作
private Lock writeLock = rwl.writeLock(); //得到一个写锁,排斥所有其他的读操作和写操作
3)对所有访问者加读锁:
public double getTotalBalance(){
readLock.lock();
try{...}
finally{readLock.unlock();}
}
4)对所有的修改者加写锁:
public void transfer(...){
writeLock.lock();
try{...}
finally{writeLock.unlock();}
}