——Java线程的实现。
——修饰符synchronized的使用。
23.1 Java线程简介
|
划分处理器时间。
可以分配处理器时间的最小单元称做“线程”。
线程的正式定义:线程是操作系统分配处理器时间的一个基本处理单元,一个进程中可以有多个线程在执行代码。线程有时也被称作轻量型进程,或者执行上下文。
23.2 创建线程
|
创建线程有两种方式:
1.扩展java.lang.Thread类。
2.实现java.lang.Runnable接口。
——大多数情况下,都不应该直接使用Thread。
每个Thread可能有6种状态之一:表示这些状态的值封装在java.lang.Thread.State枚举中。NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED.
Thread类的public构造器:
public Thread()
public Thread(String name)
public Thread(Runnable target)
public Thread(Runnable target, String name)
Thread类中部分有用的方法:
public String getName()
public Thread.State getState()
public void interrupt()
public void start()
public static void sleep(long millis)
返回当前线程
public static Thread currentThread()
23.2.1 扩展线程
——【Java不支持多重继承】
23.2.2 实现Runnable接口
如果使用的是Runnable接口,就必须传递Runnable来实例化Thread类。
RunnableTest1 test = new RunnableTest11();
Thread thread = new Thread(test);
thread.start();
23.3 使用多线程
|
23.4 线程优先级
|
为一个线程设置优先级:
public final void setPriority(int priority)
23.5 停止线程
|
使用带条件的while循环。
在类中,需要提供一个方法来改变condition的值:
public synchronized void stopThread(){
condition = false;
}
23.6 同步
|
Java提供了并发工具(Concurrency Utility),其中包含更好的锁(lock)所以应该尽量使用这些锁来代替synchronized。
23.6.1 线程冲突
两个非原子的操作在不同的线程中运行,却操作同一个数据,其中的交叉就称作线程冲突。
——原子操作:
在Java中,除long和double之外的所有基本类型都可以以原子方式读取和写入。
——线程安全性:
线程冲突会导致一个竞争状况。它是指多个线程同时在读取或者写入某些共享数据,其结果是无法预计的。
23.6.2 方法同步
每个Java对象都有一个内在锁(Intrinsic lock),有时也称为监视器锁(monitor lock)。获得对象的内在锁,是能够独占该对象访问权的一种方式。
修饰符synchronized可以用来锁定一个对象。当一个线程调用一个非静态的同步方法时,它会在该方法可以执行之前,自动尝试获取该方法对象的内在锁。
锁是可重入的。这意味着占用锁的线程额可以调用同一个对象中的同步方法。当这个方法返回时,释放内在锁。
在一个程序内部,保证一次只有一个线程能够访问某个共享资源的代码片段称作临界区。在Java中临界区是利用关键字synchronized实现的。
23.6.3 块同步
synchronized(Object){
//在锁定对象时做些操作
}
UserStat userStat = new UserStat();
...
public void incrementCounter(){
synchronized(userStat){
//要同步的语句
userStat.increment();
}
}
——方法同步和锁定当前对象的块同步是一样的效果。
23.7 可见性
|
由于Java的内存模型,一个线程是看不到另一个线程所做的修改的,除非对数据的操作方法是同步的。
同步对started的访问:
public synchronized static void setStarted(){
started = true;
}
public synchronized static boolean getStarted(){
return started;
}
注意,同步是要付出代价的,锁定一个对象会产生运行时开销。
如果追求的是可见性,并且不需要互相排他性,那么就可以用关键字volatile代替synchronized。
将一个变量声明为volatile就可以确保访问该变量的所有线程都能够见到它。
static volatile boolean started = false;
注意,虽然volatile解决了可见性的问题,但它不能用来解决互斥问题。
23.8 线程协调
|
public final void wait() throws InterruptedException
在同步方法中,使得正在访问同步方法的主调线程把自己放在等待状态,放弃对象锁定。
public final void wait(long timeout) throws InterruptedException
public final void notify()
通知一个正在等待这个对象的锁的线程。
public final void notifyAll()
23.9 使用Timer
|
java.util.Timer类提供了另一种执行规划好的任务,或者循环任务的方法。
创建一个Timer后就调用它的schedule方法,传递一个java.util.TimerTask对象,后者包含需要Timer执行的代码。