------- android培训、java培训、期待与您交流! ----------
一、线程间通讯
所谓线程间通讯,其实就是多个线程在操作同一资源,但操作的动作不同。
在Java1.5版本之前,实现线程间通讯的解决方案是:等待唤醒机制。
该机制用到了Object类中的3个方法:wait()、notify()、notifyAll()。
这3个方法都使用在同步中,因为要对持有对象监视器(锁)的线程操作,只有同步才具有锁。
之所以定义在Object类中,是因为这些方法在操作同步中线程时,都必须标识它们所操作线程持有的锁,只有同一个锁上的被等待进程,可以被同一个锁上notify唤醒,不可以唤醒不同锁中的线程。而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中。
例如在下面“生产者和消费者”这个例子中,有2个生产者和2个消费者总共4个线程,每次操作共享数据时都用while(flag)判断资源标记来决定是否需要wait(),在操作完共享数据后使用notifyAll()唤醒所有生产者线程和消费者线程。
class Resource {
private String name;
private int count = 1;
private boolean flag = false;
public synchronized void set(String name) {
while(flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name + count ++;
System.out.println(Thread.currentThread().getName() + "...生产.." + this.name);
flag = true;
this.notifyAll();
}
public synchronized void out() {
while(!flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "...消费...." + name );
flag = false;
this.notifyAll();
}
}
在Java1.5版本之后,Java提供了一种新的线程间通讯的解决方案:Lock 和 Condition
Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性, 可以支持多个相关的 Condition 对象。Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。
这个解决方案意味着可以唤醒特定的线程,比唤醒所有线程效率更高。
用这个方法改进后的完整程序代码如下:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Resource {
private String name;
private int count = 1;
private boolean flag = false;
private final Lock lock = new ReentrantLock();
private final Condition condition_pro = lock.newCondition();
private final Condition condition_con = lock.newCondition();
public void set(String name) throws InterruptedException {
lock.lock();
try {
while(flag) {
condition_pro.await();
}
this.name = name + count ++;
System.out.println(Thread.currentThread().getName() + "...生产.." + this.name);
flag = true;
condition_con.signal();
}
finally {
lock.unlock();
}
}
public synchronized void out() throws InterruptedException {
lock.lock();
try {
while(!flag) {
condition_con.await();
}
System.out.println(Thread.currentThread().getName() + "...消费...." + name );
flag = false;
condition_pro.signal();
}
finally {
lock.unlock();
}
}
}
class Producer implements Runnable {
private Resource r;
Producer(Resource r) {
this.r = r;
}
public void run() {
for(int x = 0; x < 100; x++) {
try {
r.set("cola");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
private Resource r;
Consumer(Resource r) {
this.r = r;
}
public void run() {
for(int x = 0; x < 100; x++) {
try {
r.out();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ProducerConsumer {
public static void main(String[] args) {
Resource r = new Resource();
new Thread(new Producer(r)).start();
new Thread(new Producer(r)).start();
new Thread(new Consumer(r)).start();
new Thread(new Consumer(r)).start();
}
}
二、停止线程
注:stop方法已过时不再使用。
1.定义循环结束标记
因为线程运行代码一般都是循环,只要控制了循环即可。
class StopDemo implements Runnable {
private boolean flag = true;
public void run() {
while(flag) {
System.out.println(Thread.currentThread().getName()+"...run");
}
}
public void changeFlag() {
flag = false;
}
}
但这个方法有一种特殊情况会无法停止线程:当线程处于冻结状态,就不会读取到flag标记,线程就不会结束。
于是有了下面的第2种方法。
2.使用interrupt(中断)方法
该方法是结束线程的冻结方法,使线程回到运行状态中来。
这样就可以操作flag标记让线程结束。
class StopDemo implements Runnable {
private boolean flag = true;
public synchronized void run() {
while(flag) {
try {
wait();
} catch (InterruptedException e) {
flag = false;
}
System.out.println(Thread.currentThread().getName()+"...run");
}
}
}
三、守护线程
public final void setDaemon(boolean on)
将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。
该方法必须在启动线程前调用。
参数on
- 如果为 true
,则将该线程标记为守护线程。
四、优先级
public final void setPriority(int newPriority)
更改线程的优先级。
参数:newPriority
- 要为线程设定的优先级(1~10)。
static int MAX_PRIORITY
线程可以具有的最高优先级(10)。
static int MIN_PRIORITY
线程可以具有的最低优先级(1)。
static int NORM_PRIORITY
分配给线程的默认优先级(5)。
五、join和yield
public final void join() throws InterruptedException
等待该线程终止。
该方法可以指定某一个线程加入,当该线程执行完毕再继续执行原线程。
public static void yield()
暂停当前正在执行的线程对象,并执行其他线程。
该方法可以稍微减缓线程运行,达到各线程都有机会平均运行的效果。
六、用匿名内部类写多线程
//第一种
new Thread() {
public void run() {
//运行代码
}
}.start();
//第二种
Runnable r = new Runnable() {
public void run() {
//运行代码
}
};
new Thread(r).start();