【黑马程序员】多线程(二) 第十二天

-------  android培训java培训java学习型技术博客、期待与您交流! ----------

知识点


01)线程间通信——示例代码



public class InputOutputThread {
	public static void main(String[] args) {
		Res r = new Res();//资源
		Input in = new Input(r);
		Output out = new Output(r);
		Thread t1 = new Thread(in);
		Thread t2 = new Thread(out);
		t1.start();
		t2.start();
	}
}
class Res{
	String name;
	String an;
}
class Input implements Runnable{
	private Res r;
	Input(Res r){
		this.r = r;
	}
	public void run(){
		int x = 0;
		while(true){
			if (x == 0){
				r.name = "汤姆";
				r.an = "猫咪";
			}else{
				r.name = "杰瑞";
				r.an = "老鼠";
			}
			x = (x + 1) % 2;
		}
	}
}
class Output implements Runnable{
	private Res r;
	Output(Res r){
		this.r = r;
	}
	public void run(){	
		while(true)
			System.out.println(r.name + "是: " + r.an);
	}
}//陷入死循环中~

02)解决安全问题。

public class InputOutputThread_2 {
	public static void main(String[] args) {
		Res_2 r = new Res_2();//资源
		Input_2 in = new Input_2(r);
		Output_2 out = new Output_2(r);
		Thread t1 = new Thread(in);
		Thread t2 = new Thread(out);
		t1.start();
		t2.start();
	}
}
class Res_2{
	String name;
	String an;
}
class Input_2 implements Runnable{
	private Res_2 r;
	Input_2(Res_2 r){
		this.r = r;
	}
	public void run(){
		int x = 0;
		while(true){
			synchronized(r){//同一个锁。
				if (x == 0){
					r.name = "汤姆";
					r.an = ".猫.咪.";
				}else{
					r.name = "杰瑞";
					r.an = "老...鼠";
				}
				x = (x + 1) % 2;
			}
		}
	}
}
class Output_2 implements Runnable{
	private Res_2 r;
	Output_2(Res_2 r){
		this.r = r;
	}
	public void run(){	
		while(true)
			synchronized(r){//同一个锁。
				System.out.println(r.name + "是: " + r.an);
			}
	}
}

03)等待唤醒机制

/*
 * 等待唤醒机制。
 * 
 * wait();
 * notify();
 * notifyAll();
 * 都使用在同步中,因为要对持有监视器(锁)的线程进行操作。
 * 所以要使用在同步中,因为只有同步才具有锁。
 * 
 * 为什么这些操作线程的方法要定义在Object类中呢?
 * 因为这些方法在操作同步中线程时,都必须要标识它们所操作线程所持有的锁。
 * 只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒,不可以对不同锁上的notify唤醒。
 * 也就是等待和唤醒必须是在同一个锁内。
 * 而锁可以是任意对象,所以可以被任意对象调用的方法就定义在Object类中。
 */
public class InputOutputThread_3 {
	public static void main(String[] args) {
		Res_3 r = new Res_3();//资源
		Input_3 in = new Input_3(r);
		Output_3 out = new Output_3(r);
		Thread t1 = new Thread(in);
		Thread t2 = new Thread(out);
		t1.start();
		t2.start();
	}
}
class Res_3{
	String name;
	String an;
	boolean flag = false;
}
class Input_3 implements Runnable{
	private Res_3 r;
	Input_3(Res_3 r){
		this.r = r;
	}
	public void run(){
		int x = 0;
		while(true){
			synchronized(r){//同一个锁。
				if (r.flag)//如果为真,等待。
					try{r.wait();}catch(Exception e){}
				if (x == 0){
					r.name = "汤姆";
					r.an = ".猫.咪.";
				}else{
					r.name = "杰瑞";
					r.an = "老...鼠";
				}
				x = (x + 1) % 2;
				r.flag = true;//将flag设置为真。
				r.notify();//唤醒另外一个线程。
			}
		}
	}
}
class Output_3 implements Runnable{
	private Res_3 r;
	Output_3(Res_3 r){
		this.r = r;
	}
	public void run(){	
		while(true){
			synchronized(r){//同一个锁。
				if (!r.flag)//如果为假,等待。
					try{r.wait();}catch(Exception e){}
				System.out.println(r.name + "是: " + r.an);
				r.flag = false;//将falg设置为false。
				r.notify();//唤醒另外一个线程。
			}
		}
	}
}

04)代码优化

/*
 * 代码的优化。
 */
public class InputOutputYouHua {
	public static void main(String[] args) {
		ResY r = new ResY();//资源
		new Thread(new InputY(r)).start();
		new Thread(new OutputY(r)).start();
	}
}
class ResY{
	String name;
	String an;
	boolean flag = false;
	public synchronized void set(String name, String an){
		if (flag)
			try{this.wait();}catch(Exception e){}
		this.name = name;
		this.an = an;
		this.flag = true;//将flag设置为真。
		this.notify();//唤醒另外一个线程。
	}
	public synchronized void out(){
		if (!flag)
			try{this.wait();}catch(Exception e){}
		System.out.println(name + "是: " + an);
		this.flag = false;//将flag设置为真。
		this.notify();//唤醒另外一个线程。
	}
}
class InputY implements Runnable{
	private ResY r;
	InputY(ResY r){
		this.r = r;
	}
	public void run(){
		int x = 0;
		while(true){
				if (x == 0)
					r.set("汤姆", ".猫.咪.");
				else
					r.set("杰瑞", "老...鼠");
				x = (x + 1) % 2;
		}
	}
}
class OutputY implements Runnable{
	private ResY r;
	OutputY(ResY r){
		this.r = r;
	}
	public void run(){	
		while(true)
			r.out();
	}
}

05)线程中通信——生产者消费

/*
 * 对于多个生产者和消费者。
 * 为什么要定义while判断标记。
 * 原因:需要让被唤醒的线程再一次判断标记。
 * 
 * 为什么定义notifyAll();
 * 因为需要唤醒对方的线程。
 * 因为只有notify()的话,容易只唤醒本方线程的情况。导致程序中的所有线程都等待。
 */
public class PrdCemDemo {
	public static void main(String[] args) {
		Resource r = new Resource();//共享资源
		new Thread(new Producer(r)).start();//生产线程0
		new Thread(new Producer(r)).start();//生产线程1
		new Thread(new Consumer(r)).start();//消费线程2
		new Thread(new Consumer(r)).start();//消费线程3
	}
}
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(Exception e){
				
			}
		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(Exception e){
				
			}
		System.out.println(Thread.currentThread().getName() + "...消费者..." + this.name);
		flag = false;
		this.notifyAll();
	}
}

class Producer implements Runnable{
	private Resource r;
	Producer(Resource r){
		this.r = r;
	}
	public void run(){
		while(true){
			r.set("+商品+");
		}
	}
}
class Consumer implements Runnable{
	private Resource r;
	Consumer(Resource r){
		this.r = r;
	}
	public void run(){
		while(true){
			r.out();
		}
	}
}
运行结果如下图所示:


06)生产消费者升级版(JDK1.5版本开始之后)

/*
 * 从JDK1.5版本开始,提供了多线程的解决方案。
 * 将同步synchronzied替换成现有的Lock方案。
 * 将Object中的wait、notify、notifyAll,替换成了Condition对象。
 * 该对象可以Lock锁,进行获取。
 */
public class PrdCemSuperDemo {
	public static void main(String[] args) {
		ResourceSup r = new ResourceSup();//共享资源
		new Thread(new ProducerSup(r)).start();//生产线程0
		new Thread(new ProducerSup(r)).start();//生产线程1
		new Thread(new ConsumerSup(r)).start();//消费线程2
		new Thread(new ConsumerSup(r)).start();//消费线程3
	}
}
class ResourceSup{
	private String name;
	private int count = 1;
	private boolean flag = false;
	private Lock lock = new ReentrantLock();
	private Condition con_c = lock.newCondition();//生产者标记
	private Condition con_p = lock.newCondition();//消费者标记
	public void set(String name) throws InterruptedException{//生产商品
		lock.lock();//获取锁。
		try{
			while (flag)
				con_c.await();//生产者线程等待。
			this.name = name + "----" + count++;
			System.out.println(Thread.currentThread().getName() + "...生产者" + this.name);
			flag = true;
			con_p.signal();//唤醒消费者线程。
		}finally{
			lock.unlock();//释放锁
		}
	}
	public void out() throws InterruptedException{//出售商品
		lock.lock();//获取锁
			try{
				while (!flag)
					con_p.await();//消费者线程等待。
				System.out.println(Thread.currentThread().getName() + "...消费者..." + this.name);
				flag = false;
				con_c.signal();//唤醒生产者线程。
			}finally{
				lock.unlock();//释放锁。
			}
	}
}

class ProducerSup implements Runnable{
	private ResourceSup r;
	ProducerSup(ResourceSup r){
		this.r = r;
	}
	public void run(){
		while(true){
			try{
				r.set("+商品+");
			}catch(InterruptedException e){
				
			}
		}
	}
}
class ConsumerSup implements Runnable{
	private ResourceSup r;
	ConsumerSup(ResourceSup r){
		this.r = r;
	}
	public void run(){
		while(true){
			try{
				r.out();
			}catch(InterruptedException e){
				
			}
		}
	}
}


07)停止线程

/*
 * stop方法以及过时。
 * 如果停止线程?
 * 只有一种方法,run方法结束。
 * 开启多线程运行,运行代码通常都是循环结构的,只要控制住循环,就可以让run方法结束,也就是线程结束。
 * 
 * 特殊情况:当线程处于冻结状态,就不会读取到标记,那么线程就不会结束。
 * 
 * 当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结状态进行清除。
 * 强制让线程恢复到运行状态,这样就可以操作标记让线程结束。
 * Thread提供了该方法:interrupt()
 */
public class StopThreadDemo {
	public static void main(String[] args) {
		StopThread st = new StopThread();
		Thread t1 = new Thread(st);
		Thread t2 = new Thread(st);
		
		int num = 0;
		while(true){
			if(num++ == 60){
//				st.ChangeFlag();
				t1.interrupt();//强制清除状态。
				t2.interrupt();
				break;
			}
			System.out.println(Thread.currentThread().getName() + "...." + num);
		}
		
	}
}

class StopThread implements Runnable{
	private boolean flag = true;
	public synchronized void run(){
		while(flag){
			try{
				wait();
			}catch(InterruptedException e){
				System.out.println(Thread.currentThread().getName() + " ... InterruptedException");
				flag = false;
			}
			System.out.println(Thread.currentThread().getName() + " ... run");
		}
	}
//	public void ChangeFlag(){
//		flag = false;
//	}
}

08)守护线程

/*
 * 设置守护线程:setDaemon(true);也就是后台线程。
 * 注意:必须在开启线程之前设置。
 */
public class SetDaemonThreadDemo {
	public static void main(String[] args) {
		SetDaemonThread st = new SetDaemonThread();
		Thread t1 = new Thread(st);
		Thread t2 = new Thread(st);
		
		t1.setDaemon(true);//设置为守护线程,也就是后台线程。
		t2.setDaemon(true);//注意:必须在开启线程之前设置。
		t1.start();
		t2.start();
		
		int num = 0;
		while(true){
			if(num++ == 60){
//				t1.interrupt();//强制清除状态。
//				t2.interrupt();
				break;
			}
			System.out.println(Thread.currentThread().getName() + "...." + num);
		}
	}
}

class SetDaemonThread implements Runnable{
	private boolean flag = true;
	public void run(){
		while(flag){
			System.out.println(Thread.currentThread().getName() + " ... run");
		}
	}
}

09)join方法

/*
 * Join:
 * 当t2线程执行到了t1线程的.join方法时,t2就会等待,等t1线程执行完,t2才会执行。
 * join用来临时加入线程执行。
 */
public class JoinThreadDemo {
	public static void main(String[] args) throws InterruptedException{
		JoinThread jt = new JoinThread();
		Thread t1 = new Thread(jt);
		Thread t2 = new Thread(jt);
		t1.start();
		t1.join();//t1申请cup执行权。主线程main放弃执行权,变更为冻结状态。
		t2.start();
		for(int i = 0; i < 80; i++){
			System.out.println("Main..." + i);
		}
	}
}
class JoinThread implements Runnable{
	public void run(){
		for(int i = 0; i < 70; i++){
			System.out.println(Thread.currentThread().getName() + "..." + i);
		}
	}
}

10) 优先级

public class ToStringThreadDemo {
	public static void main(String[] args) throws InterruptedException{
		ToStringThread jt = new ToStringThread();
		Thread t1 = new Thread(jt);
		Thread t2 = new Thread(jt);
		t1.start();
//		t1.setPriority(Thread.MAX_PRIORITY);//设置优先级
		t2.start();
		for(int i = 0; i < 80; i++){
			System.out.println(Thread.currentThread().toString() + "Main..." + i);
		}
	}
}
class ToStringThread implements Runnable{
	public void run(){
		for(int i = 0; i < 70; i++){
			System.out.println(Thread.currentThread().toString() + "..." + i);
			Thread.yield();//暂停当前正在执行的线程对象,并执行其他线程。
		}
	}
}


附言:我是Java新人,如有错误的地方请指出。
                         每天学习一点点,纠错一点点,进步很大点。



-------  android培训java培训java学习型技术博客、期待与您交流! ----------


阅读更多
个人分类: 【黑马程序员】
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭