关闭

黑马程序员_多线程2

193人阅读 评论(0) 收藏 举报
分类:

------- 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();


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:2089次
    • 积分:115
    • 等级:
    • 排名:千里之外
    • 原创:10篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章存档