黑马程序员 java学习笔记——多线程2

---------------------- ASP.Net+Android+IO开发S.Net培训、期待与您交流! ----------------------

线程间通讯示例代码:

class Res{
	String name;
	String sex;
}

class A implements Runnable{
	Res res;
	A(Res res){
		this.res=res;
	}
	public void run(){
		int num=0;
		while(true){
			synchronized(res){
				if(num==0){
					res.name="wang...wang...wang...wang";
					res.sex="nan...nan...nan...nan";
				}else{
					res.name="zhao";
					res.sex="nv";
				}
				num=(num+1)%2;
			}
		}
	}
}
class B implements Runnable{
	Res res;
	B(Res res){
		this.res=res;
	}
	public void run(){
		while(true){
			synchronized(res){
				System.out.println(res.name+"........"+res.sex);
			}
		}
	}
}
public class AtoB {
	public static void main(String[] args){
		Res res=new Res();
		new Thread(new A(res)).start();
		new Thread(new B(res)).start();
	}
}

等待唤醒机制

代码示例如下:
class Rec1{
	String name;
	String sex;
	boolean flag;
}
class A1 implements Runnable{
	Rec1 rec;
	A1(Rec1 rec){
		this.rec=rec;
	}
	public void run(){
		int num=0;
		while(true){
			synchronized(rec){
				if(rec.flag)
					try{
						rec.wait();
					}catch(InterruptedException e){
						System.out.println(e);
					}
				if(num==0){
					rec.name="wang...wang...wang...wang";
					rec.sex="nan...nan...nan...nan";
				}else{
					rec.name="zhao";
					rec.sex="nv";
				}
				num=(num+1)%2;
				rec.flag=true;
				rec.notify();
			}
		}
	}
}
class B1 implements Runnable{
	Rec1 rec;
	B1(Rec1 rec){
		this.rec=rec;
	}
	public void run(){
		while(true){
			synchronized(rec){
				if(!rec.flag)
					try{
						rec.wait();
					}catch(InterruptedException e){
						System.out.println(e);
					}
				System.out.println(rec.name+"........"+rec.sex);
				rec.flag=false;
				rec.notify();
			}
		}
	}
}
public class AtoB2 {
	public static void main(String[] args){
		Rec1 rec=new Rec1();
		new Thread(new A1(rec)).start();
		new Thread(new B1(rec)).start();
	}
}

1、notify唤醒线程池中的线程
2、操作共享数据的对象分属不同的类,锁要选一样的,如A.class,或者rec。
3、wait、notif、notifyALL 这三个都使用在同步中,因为要对持有监视器(锁)的线程操作,所以要使用在同步中,因为只有同步才有锁。

为什么这些操作线程的方法要定义Object类中呢?

因为这些方法在操作同步中线程时,都必须要标识它们所操作线程持有的锁,只有统一个锁上的被等待线程,可以被同一个锁上notify唤醒,不可以对不同锁中的线程进行唤醒。
也就是说,等待和唤醒必须是同一个锁。而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。

优化后的代码

class Re{
	private String name;
	private String sex;
	private boolean flag;
	public synchronized void set(String name,String sex){
		if(flag){
			try{
				this.wait();
			}catch(InterruptedException e){
				System.out.println(e);
			}
		}
		this.name=name;
		this.sex=sex;
		flag=true;
		this.notify();
	}
	public synchronized void out(){
		if(!flag){
			try{
				this.wait();
			}catch(InterruptedException e){
				System.out.println(e);
			}
		}
		System.out.println(name+".........."+sex);
		flag=false;
		this.notify();
	}
}
class A3 implements Runnable{
	Re re;
	A3(Re re){
		this.re=re;
	}
	public void run(){
		int num=0;
		while(true){
			if(num==0)
				re.set("wang","nan");
			else
				re.set("li","nv");
			num=(num+1)%2;
		}
	}
}
class B3 implements Runnable{
	Re re;
	B3(Re re){
		this.re=re;
	}
	public void run(){
		while(true){
			re.out();
		}
	}
}
public class AtoB3 {
	public static void main(String[] args){
		Re re=new Re();
		new Thread(new A3(re)).start();
		new Thread(new B3(re)).start();
	}
}

生产消费者问题

上面的例子中,都是一个输入一个输出,如果它们都不再是单一的,情况又是怎样的呢?
示例代码如下:
class Res{
	private String name;
	private int count=1;
	private boolean flag;
	public synchronized void set(String name){
		while(flag)
			try{this.wait();}catch(InterruptedException 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(InterruptedException e){}
		System.out.println(Thread.currentThread().getName()+"...消费者"+this.name);
		flag=false;
		this.notifyAll();
	}
}

class Input implements Runnable{
	private Res res;
	Input(Res res){
		this.res=res;
	}
	public void run(){
		while(true)
			res.set("+商品+");
	}
}

class Output implements Runnable{
	private Res res;
	Output(Res res){
		this.res=res;
	}
	public void run(){
		while(true)
			res.out();
	}
}


public class Demo{
	public static void main(String[] args){
		Res res=new Res();
		new Thread(new Input(res)).start();
		new Thread(new Output(res)).start();
		new Thread(new Input(res)).start();
		new Thread(new Output(res)).start();
	}
}

问题:

notifyAll唤醒所有线程,这样不好,怎么才能只唤醒对方线程呢?
JDK5.0中提供了多线程升级解决方法。
将同步synchronized替换成显式Lock操作,将Object中的wait、notify、notifyAll,替换成了condition,该对象可以lock锁,进行获取。
下面的示例代码中,实现了本方只唤醒对方的操作。
import java.util.concurrent.locks.*;
class Res{
	private String name;
	private int count;
	private boolean flag;

	private Lock lock=new ReentrantLock();
	private Condition condition_1=lock.newCondition();
	private Condition condition_2=lock.newCondition();

	public void set(String name){
		lock.lock();
		try{
			while(flag)
				condition_1.await();
			this.name=name+"--"+count++;
			System.out.println(Thread.currentThread().getName()+"...生产者......."+this.name);
			flag=true;
			condition_2.signal();
		}catch(InterruptedException e){
			System.out.println(e);
		}finally{
			lock.unlock();
		}
	}
	public void out(){
		lock.lock();
		try{
			while(!flag)
				condition_2.await();
				System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name);
				flag=false;
				condition_1.signal();
		}catch(InterruptedException e){
			System.out.println(e);
		}finally{
			lock.unlock();
		}
	}
}
class Productor implements Runnable{
	private Res res;
	Productor(Res res){
		this.res=res;
	}
	public void run(){
		while(true)
			res.set("+商品+");
	}
}
class Consumer implements Runnable{
	private Res res;
	Consumer(Res res){
		this.res=res;
	}
	public void run(){
		while(true)
			res.out();
	}
}
public class Demo{
	public static void main(String[] args){
		Res res=new Res();
		Productor pro=new Productor(res);
		Consumer con=new Consumer(res);

		new Thread(pro).start();
		new Thread(pro).start();
		new Thread(con).start();
		new Thread(con).start();
	}
}

停止线程

查看API文档,发现stop方法已经过时,如何停止线程呢?只有一种方法,那就是run方法结束。

方法一:定义循环结束标记

开启多线程运行,运行代码通常是循环结构,只要控制住循环,就可以让run方法结束,也就是线程结束。
示例代码如下:
class Demo implements Runnable{
	public boolean flag=true;
	public void run(){
		while(flag){
			System.out.println(Thread.currentThread().getName()+"run");
		}
	}
	public void changeFlag(){
		flag=false;
	}
}
public class StopThread {
	public static void main(String[] args){
		Demo demo=new Demo();
		new Thread(demo).start();
		new Thread(demo).start();
		int num=0;
		while(true){
			if(num++==60){
				demo.changeFlag();
				break;
			}
			System.out.println(Thread.currentThread().getName()+"-run");
		}
	}
}

方法二:使用interrupt(中断)方法

有一种特殊情况,当线程处于冻结状态,就不会读取到标记,那么线程就不会结束,这时就甬道了interrupt方法。
该方法是结束线程的冻结状态,使线程回到运行状态中来,它将受到一个InterruptedException
注意:interrupt方法并不是结束线程。
示例代码如下:
class Demo1 implements Runnable{
	public 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;
	}
}
public class StopThread2 {
	public static void main(String[] args){
		Demo1 demo=new Demo1();
		Thread t1=new Thread(demo);
		Thread t2=new Thread(demo);
		t1.start();
		t2.start();
		int num=0;
		while(true){
			if(num++==60){
				t1.interrupt();
				t2.interrupt();
				break;
			}
			System.out.println(Thread.currentThread().getName()+"run");
		}
	}
}
//synchronized 加到方法之上,该方法仍旧算复写。

实际开发中线程的写法展示

当某些代码需要同时进行时,就需要单独的封装。
示例代码如下:
public class ThreadTest {
	public static void main(String[] args){
		for(int i=0;i<50;i++){
			System.out.println(Thread.currentThread().getName()+"  "+i);
		}
		//匿名内部类
		new Thread(){
			public void run(){
				for(int i=0;i<50;i++){
					System.out.println(Thread.currentThread().getName()+"  "+i);
				}
			}
		};
		
		Runnable r=new Runnable(){
			public void run(){
				for(int i=0;i<50;i++){
					System.out.println(Thread.currentThread().getName()+"  "+i);
				}
			}
		};
		new Thread(r).start();
	}
}

----------------------  ASP.Net+Android+IO开发S .Net培训 、期待与您交流! ----------------------
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值