黑马程序员——Java继承——多线程(二)

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

本人习惯将总结写在代码里~

线程间通信问题:

package cn.fuxi.duoxiancheng2;
/**
 * 线程间通信
 * 多线程在处理统一资源,但是任务却不同,这时候就需要线程间通信.
 * 等待/唤醒机制涉及的方法:
 * 1.wait():让线程处于冻结状态,被wait的线程会被存储到线程池中.
 * 2.notify():唤醒线程池中的一个线程(任何一个都有可能).
 * 3.notifyAll():唤醒线程池中的所有线程.
 * 
 * P.S.
 * 1.这些方法都必须要定义在同步中,因为这些方法是用于操作线程状态的方法.
 * 2.必须要明确到底操作的是哪个锁上的线程!
 * 3.wait和sleep的区别?
 * 		1--wait可以指定时间也可以不指定.sleep必须指定时间.
 * 		2--在同步中时,对cpu的执行权和锁的处理不同.
 * wait:释放执行权,释放锁.
 * sleep:释放执行权,不释放锁.
 * 
 * 为什么线程操作的方法wait\notify\notifyAll定义在了Object类中?
 * 因为这些方法是监视器的方法,监视器其实就是锁.
 * 锁可以是任意的对象,任意的对象调用的方式一定在Object类中.
 */
//生产者-消费者问题:
class Resource{
	private String name;
	private String sex;
	private boolean flag = false;
	
	public synchronized void set(String name,String sex){
		if(flag)
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		this.name = name;
		this.sex = sex;
		flag = true;
		this.notify();
	}
	public synchronized void out(){
		if(!flag)
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		System.out.println(name+"..."+sex);
		flag = false;
		this.notify();
	}
}
class Input implements Runnable{
	Resource r;
	Input(Resource r){
		this.r = r;
	}
	public void run(){
		int x = 0;
		while (true){
			if(x==0){
				r.set("mike","男");
			}else{
				r.set("lili", "女");
			}
			x = (x+1)%2;
		}
	}
}
//输出
class Output implements Runnable{
	Resource r;
	Output(Resource r){
		this.r = r;
	}
	public void run(){
		while(true){
			r.out();
		}
	}
}
public class ThreadDemo1 {
	public static void main(String[] args) {
		//创建资源
		Resource r = new Resource();
		//创建任务
		Input in = new Input(r);
		Output out = new Output(r);
		//创建线程,执行路径
		Thread t1 = new Thread(in);
		Thread t2 = new Thread(out);
		//开启线程
		t1.start();
		t2.start();
	}
}
运行结果:

lili...女
mike...男
lili...女
mike...男
lili...女
mike...男
lili...女
mike...男
lili...女
mike...男
lili...女
mike...男
lili...女
mike...男
lili...女


生产者消费者问题:

package cn.fuxi.duoxiancheng2;
/**
 * 多生产者-多消费者问题
 */
class Resource2{
	private String name;
	private int count =1;
	private boolean flag = false;
	public synchronized void set(String name){
		if(flag)
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		this.name = name+count;
		count++;
		System.out.println(Thread.currentThread().getName() + "...生产者..."+ this.name);
		flag = true;
		notify();
	}
	public synchronized void out(){
		if(!flag)
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		flag = false;
		notify();
		System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name);
	}
}

class Producer implements Runnable{
	private Resource2 r;
	Producer(Resource2 r){
		this.r = r;
	}
	public void run(){
		while(true){
			r.set("烤全羊");
		}
	}
}
class Consumer implements Runnable{
	private Resource2 r;
	Consumer(Resource2 r){
		this.r = r;
	}
	public void run(){
		while(true){
			r.out();
		}
	}
}
public class ThreadDemo2 {

	public static void main(String[] args) {
		Resource2 r = new Resource2();
		Producer pro = new Producer(r);
		Consumer con = new Consumer(r);
		
		Thread tp1 = new Thread(pro);
		Thread tp2 = new Thread(pro);
		Thread tc3 = new Thread(con);
		Thread tc4 = new Thread(con);
		tp1.start();
		tp2.start();
		tc3.start();
		tc4.start();//出现多消费者消费同一只烤全羊
	}
}
/*
 *原因分析:
 *1.线程Thread-1获取的cpu执行权及锁,生产了烤全羊123,将flag设置为true.然后,Thread-1又
 *重新获取到cpu执行权,由于flag为true,故执行wait方法,阻塞.Thread-2接着获取到CPU执行权,
 *由于flag为true,故执行wait方法,也阻塞.
 *2.线程Thread-4获取到CPU执行权及锁,消费了烤全羊123,将flag设置为false.然后线程Thread-1
 *被唤醒,但是并没有获取到锁,而是线程Thread-4接着获取到CPU执行权及锁,然而此时flag为false,所以
 *Thread-4阻塞,之后Thread-3接着获取到CPU执行权及锁,然而flag为false,所以Thread-3也阻塞.
 *3.线程Thread-1获取到CPU执行权及锁,不需要if判断,直接生产124,然后又唤醒线程Thread-2获取到
 *执行权及锁,不需要if判断,直接生产125,从而造成烤全羊124还没有消费,就生产了125的情况.
 */

运行结果:

Thread-2...消费者...烤全羊21949
Thread-1...生产者...烤全羊21950
Thread-0...生产者...烤全羊21951
Thread-3...消费者...烤全羊21951
Thread-2...消费者...烤全羊21951
Thread-1...生产者...烤全羊21952
Thread-0...生产者...烤全羊21953
Thread-3...消费者...烤全羊21953
Thread-2...消费者...烤全羊21953
Thread-1...生产者...烤全羊21954
Thread-0...生产者...烤全羊21955
Thread-3...消费者...烤全羊21955
Thread-2...消费者...烤全羊21955


改进:

package cn.fuxi.duoxiancheng2;
/**
 * 由于if判断标记,只有一次,会导致不该运行的线程运行了,出现了数据错误的情况.故修改成while判断标记,
 * 线程获取CPU执行权及锁后,将重新判断是否具备运行条件.
 * notify只能唤醒一个线程,如果本方唤醒了本方,没有意义.而且while判断标记+notify会导致死锁.notifyAll
 * 解决了本方线程一定会唤醒对方线程的问题.
 * 
 * P.S.
 * while判断标记+notify会导致死锁的示例:
 * 如果将上面的代码中的if判断标记修改成wile判断标记,就会出现死锁的现象,前2步与原来是一致的.
 * 第三步如下:
 * 3.线程Thread-1获取到CPU执行权及锁,通过while语句判断,直接生产烤全羊124,将flag设置为true.
 * 然后又唤醒线程Thread-2获取到CPU执行权及锁,没有通过while语句判断,阻塞.线程Thread-1又获取到
 * CPU执行权及锁,通不过while语句判断,也阻塞,此时Thread-1,2,3,4都阻塞,故死锁.
 */

class Resource3{
	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;
		count++;
		System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);
		flag = true;
		notifyAll();
	}
	public synchronized void out(){
		while(!flag)
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name);
		flag = false;
		notifyAll();
	}
}
class Producer3 implements Runnable{
	private Resource3 r;
	Producer3(Resource3 r){
		this.r = r;
	}
	public void run(){
		while(true){
			r.set("烤鸭");
		}
	}
}
class Consumer3 implements Runnable{
	private Resource3 r;
	Consumer3(Resource3 r){
		this.r = r;
	}
	public void run(){
		while(true){
			r.out();
		}
	}
}
public class ThreadDemo3 {
	public static void main(String[] args) {
		Resource3 r = new Resource3();
		Producer3 pro = new Producer3(r);
		Consumer3 con = new Consumer3(r);
		Thread t1 = new Thread(pro); 
		Thread t2 = new Thread(pro); 
		Thread t3 = new Thread(con); 
		Thread t4 = new Thread(con);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}

}
运行结果:

Thread-2...消费者...烤鸭54351
Thread-0...生产者...烤鸭54352
Thread-3...消费者...烤鸭54352
Thread-1...生产者...烤鸭54353
Thread-2...消费者...烤鸭54353
Thread-0...生产者...烤鸭54354
Thread-3...消费者...烤鸭54354
Thread-1...生产者...烤鸭54355
Thread-2...消费者...烤鸭54355
Thread-0...生产者...烤鸭54356
Thread-3...消费者...烤鸭54356
Thread-1...生产者...烤鸭54357
Thread-2...消费者...烤鸭54357
Thread-0...生产者...烤鸭54358

JDK1.5新特性:

package cn.fuxi.duoxiancheng2;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * JDK1.5新特性
 * 同步代码块,就是对于锁的操作是隐式的.
 * JDK1.5以后将同步和锁封装成了对象,并将操作锁的隐式方式定义到了该对象中,将隐式动作变成了显示动作.
 * Lock接口:出现替代了同步代码块或者同步函数,将同步的隐式操作变成显示锁操作,同时更为灵活,可以一个锁
 * 加上多组监视器.
 * lock():获取锁.
 * unlock():释放锁,未来防止出现异常,导致锁无法被关闭,所以锁的关闭动作要放在finally中.
 * Condition接口:出现替代了Object中的wait,notify,notifyAll方法,将这些监视器方法单独经行了
 * 封装,变成Condition监视器对象,可以任意锁进行组合.
 * Condition接口中的await方法对应于Object中的wait方法.
 * Condition接口中的signal方法对应于Object中的notify方法.
 * Condition接口中的signalAll方法对应于Object中的notifyAll方法.
 * 
 * 使用一个Lock,一个Condition修改多生产者,多消费者的问题.
 */

class Resource6{
	private String name;
	private int count = 1;
	private boolean flag = false;
	
	//创建一个锁对象
	Lock lock = new ReentrantLock();
	
	//通过已有的锁获取该锁上的监视器对象
	Condition con = lock.newCondition();
	
	public void set(String name){
		lock.lock();
		try{
			while(flag)
				try {
					con.await();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			this.name = name +count;
			count++;
			System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);
			flag = true;
			con.signalAll();
		}finally{
			lock.unlock();
		}	
	}
	public void out(){
		lock.lock();
		try{
			while(!flag)
				try {
					con.await();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			flag = false;
			con.signalAll();
			System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name);
		}finally{
			lock.unlock();
		}
	}
}
class Producer6 implements Runnable{
	private Resource6 r ;
	Producer6(Resource6 r){
		this.r = r;
	}
	public void run(){
		while(true){
			r.set("烤鸭");
		}
	}
}
class Consumer6 implements Runnable{
	private Resource6 r;
	Consumer6(Resource6 r){
		this.r = r;
	}
	public void run(){
		while(true){
			r.out();
		}
	}
}

public class ThreadDemoJDK5 {

	public static void main(String[] args) {
		Resource6 r = new Resource6();
		Producer6 pro = new Producer6(r);
		Consumer6 con = new Consumer6(r);
		
		Thread t1 = new Thread(pro);
		Thread t2 = new Thread(pro);
		Thread t3 = new Thread(con);
		Thread t4 = new Thread(con);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}

}
运行结果:

Thread-1...生产者...烤鸭17875
Thread-3...消费者...烤鸭17875
Thread-1...生产者...烤鸭17876
Thread-3...消费者...烤鸭17876
Thread-1...生产者...烤鸭17877
Thread-3...消费者...烤鸭17877
Thread-1...生产者...烤鸭17878
Thread-3...消费者...烤鸭17878
Thread-1...生产者...烤鸭17879
Thread-3...消费者...烤鸭17879

多线程的方法:

package cn.fuxi.duoxiancheng3;
/**
 * 停止线程
 * 怎么控制线程的任务结束呢?
 * 任务中都会有循环结构,只要控制住循环就可以结束任务.
 * 控制循环通常就是用定义标记来完成.
 */
class StopThread implements Runnable{
	private boolean flag = true;
	public void run(){
		while(flag){
			System.out.println(Thread.currentThread().getName()+"...");
		}
	}
	public void setFlag(){
		flag = false;
	}
}

public class ThreadDemo1 {
	public static void main(String[] args) {
		StopThread st = new StopThread();
		Thread t1 = new Thread(st);
		Thread t2 = new Thread(st);
		t1.start();
		t2.start();
		int num = 1;
		for(;;){
			if(++num==50){
				st.setFlag();
				break;
			}
			System.out.println("main..."+num);
		}
	}
}
运行结果:
Thread-1...
Thread-0...
Thread-1...
main...47
Thread-1...
Thread-0...
Thread-1...
main...48
Thread-1...
Thread-0...
Thread-1...
main...49
Thread-1...
Thread-0...


package cn.fuxi.duoxiancheng3;
/**
 * 如果线程处于了冻结状态,无法读取标记,如何结束呢?
 * 可以使用interruput()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备CPU的执行资格.
 * 强制动作会发生InterruptedException,一定要记得处理.
 */
class StopThread2 implements Runnable{
	private boolean flag = true;
	public synchronized void run(){
		while(flag){
			try {
				wait();
			} catch (InterruptedException e) {
				System.out.println(Thread.currentThread().getName()+"..."+e);
				flag = false;
			}
			System.out.println(Thread.currentThread().getName()+"..............");
		}
	}
	public void setFlag(){
		flag = false;
	}
}

public class ThreadDemo2 {
	public static void main(String[] args) {
		StopThread2 s2 = new StopThread2();
		Thread t1 = new Thread(s2);
		Thread t2 = new Thread(s2);
		t1.start();
		t2.start();
		int num = 1;
		for(;;){
			if(++num == 50){
				t1.interrupt();
				t2.interrupt();
				break;
			}
			System.out.println("main..."+num);
		}
		System.out.println("over");
	}
}

运行结果:

main...43
main...44
main...45
main...46
main...47
main...48
main...49
over
Thread-1...java.lang.InterruptedException
Thread-1..............
Thread-0...java.lang.InterruptedException
Thread-0..............

package cn.fuxi.duoxiancheng3;
/**
 * setPriority方法:更改线程的优先级
 * toString方法:返回该现场的字符串表示形式,包括线程名称,优先级和线程组.
 * yield方法:暂停当前正在执行的线程对象,并执行其他进程.
 * 
 */
class Demo2 implements Runnable{
	public void run(){
		for(int x = 0 ; x < 50; x++){
			System.out.println(Thread.currentThread().toString()+"..."+x);
			Thread.yield();//释放执行权
		}
	}
}
public class ThreadFangFa {
	public static void main(String[] args) {
		Demo2 d = new Demo2();
		Thread t1 = new Thread(d);
		Thread t2 = new Thread(d);
		t1.start();
		t2.start();
		t2.setPriority(Thread.MAX_PRIORITY);
		for(int x = 0;x<50;x++){
			System.out.println(Thread.currentThread().toString()+"..."+x);
		}
	}
}
运行结果:

Thread[main,5,main]...42
Thread[Thread-1,10,main]...42
Thread[main,5,main]...43
Thread[Thread-1,10,main]...43
Thread[main,5,main]...44
Thread[Thread-1,10,main]...44
Thread[main,5,main]...45
Thread[Thread-1,10,main]...45
Thread[main,5,main]...46
Thread[Thread-1,10,main]...46
Thread[main,5,main]...47
Thread[Thread-1,10,main]...47
Thread[main,5,main]...48
Thread[Thread-1,10,main]...48
Thread[main,5,main]...49
Thread[Thread-1,10,main]...49

package cn.fuxi.duoxiancheng3;
/**
 * thread.join()方法:
 * 作用:让该线程先走,结束后再执行其他线程,方便调用该线程完全结束后的结果
 */
class Demo implements Runnable{
	public void run(){
		for(int x = 0; x< 50; x++){
			System.out.println(Thread.currentThread().getName()+"..."+x);
		}
	}
}

public class JoinDemo {
	public static void main(String[] args) {
		Demo d =new Demo();
		Thread t1 = new Thread(d);
		Thread t2 = new Thread(d);
		t1.start();
		try {
			t1.join();//t1线程要申请加入进来,运行,然后主线程t1执行完毕
			//临时加入一个线程运算时可用使用join方法.
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		t2.start();
		for(int x = 0 ;x< 50 ; x++){
			System.out.println(Thread.currentThread().toString()+"..."+x);
		}
	}
}
运行结果:

Thread-0...36
Thread-0...37
Thread-0...38
Thread-0...39
Thread-0...40
Thread-0...41
Thread-0...42
Thread-0...43
Thread-0...44
Thread-0...45
Thread-0...46
Thread-0...47
Thread-0...48
Thread-0...49
Thread[main,5,main]...0
Thread-1...0
Thread[main,5,main]...1
Thread-1...1
Thread[main,5,main]...2
Thread-1...2
Thread[main,5,main]...3
Thread-1...3


package cn.fuxi.duoxiancheng3;
/**
 * 线程类其他方法
 * setDaemon();
 * 将该线程标记为守护线程或用户线程.当正在运行的线程都是守护线程时,Java虚拟机退出.
 * 该方法必须在启动线程前调用.
 */
class StopThread3 implements Runnable{
	private boolean flag = true;
	public synchronized void run(){
		while(flag){
			try {
				wait();
			} catch (InterruptedException e) {
				System.out.println(Thread.currentThread().getName()+e);
				flag = false;
			}
			System.out.println(Thread.currentThread().getName()+"...");
		}
	}
	public void setFlag(){
		flag = false;
	}
}

public class SetDaemonDemo1 {
	public static void main(String[] args) {
		StopThread3 s3 = new StopThread3();
		Thread t1 = new Thread();
		Thread t2 = new Thread();
		
		t1.start();
		t2.setDaemon(true);
		t2.start();
		int num = 1;
		for(;;){
			if(++num ==50){
				t1.interrupt();
				break;
			}
			System.out.println("main"+num);
		}
		System.out.println("over");
	}

}
运行结果:
main38
main39
main40
main41
main42
main43
main44
main45
main46
main47
main48
main49
over



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值