Java多线程 - 第三篇

一,线程的通讯

线程间通信就是多个线程在操作同一个资源,但是操作动作不同。

最经典的例子就是生产者与消费者

//产品类
class Product{
	String name;  //名字
	int price;  //价格
	boolean flag = false; //产品是否生产完毕的标识
}

//生产者
class Producer extends Thread{
	Product  p ;  	//产品	
	public Producer(Product p) {
		this.p  = p ;
	}

	@Override
	public void run() {
		int i = 0 ; 
		while(true){
		 synchronized (p) {
			if(p.flag==false){
				 if(i%2==0){
					 p.name = "产品1";
					 p.price = 100;
				 }else{
					 p.name="产品2";
					 p.price = 120;
				 }
				 System.out.println("生产者生产出了:"+ p.name+" 价格是:"+ p.price);
				 p.flag = true;
				 i++;
		
			}
			 
		}	
	  }	
	}
}


//消费者
class Customer extends Thread{	
	Product p; 
	
	public  Customer(Product p) {
		this.p = p;
	}
	
	@Override
	public void run() {
		while(true){
			synchronized (p) {	
				if(p.flag==true){  //产品已经生产完毕
					System.out.println("消费者消费了"+p.name+" 价格:"+ p.price);
					p.flag = false; 
					
				}
			}
		}	
	}
}

public class Demo4 {
	
	public static void main(String[] args) {
		Product p = new Product();  //产品

		Producer producer = new Producer(p);//生产者
		Customer customer = new Customer(p);//消费者
		//调用start方法开启线程
		producer.start();
		customer.start();

	}
	
}


wait() 是等待线程,是以锁对象为标示 把线程放到连接池中

notify():唤醒线程池等待线程其中的一个。

notify()只是唤醒线程池中已锁对象为标示 等待线程中的一个。而notifyAll()是唤醒全部已锁对象为标示的等待线程

需要注意的是 wait(),notify(),notifyAll()必须要在同步代码块中才能运行 且锁对象必须与调用方法的对象是一个也就是说必须是锁对象调用。 

二,线程的停止

线程的生命周期
1,线程正常执行完成,自动销毁
2,使用过时stop方法
方法1:
public class Demo3 extends Thread {
	@Override
	public void run() {
		System.out.println("自定义线程....");
	}
	
	public static void main(String[] args) {
		Demo3 d = new Demo3();
		d.setPriority(MAX_PRIORITY);
		d.start();
		
		for(int i=0; i<=100; i++){
			System.out.println("mian线程....");
			if(i==80){//当I==80的时候 停止线程
				d.stop();	
			}
		}
	}
}

方式二:
public class Demo3 extends Thread {
	static boolean flag = true;
	@Override
	public void run() {
		while(flag){
			System.out.println("自定义线程....");
		}
	}
	
	public static void main(String[] args) {
		Demo3 d = new Demo3();
		d.setPriority(MAX_PRIORITY);
		d.start();
		
		for(int i=0; i<=100; i++){
			System.out.println("mian线程...."+i);
			if(i==80){//当I==80的时候 停止线程
				flag = false;
			}
		}
	}
}

如果 在run 方法的后面加一个方法 wait,那么就要在if后面加静态代码块把该线程唤醒,否则线程将会一直等待 不会死亡
public class Demo3 extends Thread {
	static boolean flag = true;
	@Override
	public void run() {
		while(flag){
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println("自定义线程....");
		}
	}
	
	public static void main(String[] args) {
		Demo3 d = new Demo3();
		d.setPriority(MAX_PRIORITY);
		d.start();
		
		for(int i=0; i<=100; i++){
			System.out.println("mian线程...."+i);
			if(i==80){//当I==80的时候 停止线程
				flag = false;
				synchronized (d) {
					d.notify();
				}
			}
		}
	}
}


当然,不一定要用静态代码块来唤醒线程,还有一种比较粗鲁的方式
interrupt  把线程的等待状态强制清除,但是被清除状态的线程会接收到一个InterruptedException异常
public static void main(String[] args) {
		Demo3 d = new Demo3();
		d.setPriority(MAX_PRIORITY);
		d.start();
		
		for(int i=0; i<=100; i++){
			System.out.println("mian线程...."+i);
			if(i==80){//当I==80的时候 停止线程
				flag = false;
				d.interrupt();//把线程的等待状态强制清除,但是被清除状态的线程会接收到一个InterruptedException异常
			}
		}
	}


三,后台线程

后台线程:就是隐藏起来一直在默默运行的线程,直到进程结束。

注意:

当所有的非后台线程结束时,程序也就终止了同时还会杀死进程中的所有后台线程,也就是说,只要有非后台线程还在运行,程序就不会终止,main方法的主线程是一个非后台线程。

调用start方法之前,调用setDaemon(true)方法,才可以把该线程设置为后台线程。

使用isDaemon()查看该线程是否为后台线程(守护线程)。

线程默认为非后台线程。


那么现在模拟后台更新程序

public class Demo4  extends Thread{
	@Override
	public void run() {
		int i=0;
		while(true){
			if(i<100){
				System.out.println("已下载了"+i+"%...");
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				i++;
			}else{
				System.out.println("已下载完成,正在准备安装");
				break;
			}
		}
	}
	
	public static void main(String[] args) {
		Demo4 d = new Demo4();
		d.setDaemon(true);//设置线程是否为守护线程,true为守护线程, false为非守护线程。
		d.setPriority(MAX_PRIORITY);
		System.out.println("是否为后台线程:"+d.isDaemon());
		d.start();
		
		for(int i=0; i<100; i++){
			System.out.println("主线程...."+ i);
		}
	}
}


 
   

为了验证,当非后台线程结束时,后台线程是否终止,故意让该后台线程睡眠一会。发现只要main线程执行完毕,后台线程也就随之消亡了。

Thread的join方法

当A线程执行到了B线程Join方法时A就会等待,等B线程都执行完A才会执行,Join可以用来临时加入线程执行.

class myThread extends Thread{
	@Override
	public void run() {
		System.out.println("... 4   ...." );
		System.out.println("... 5   ...." );
	
	}
}


public class Demo5 {
	public static void main(String[] args) {
		myThread thread = new myThread();
		thread.start();
		System.out.println("... 1   ...." );
		System.out.println("... 2   ...." );
		System.out.println("... 3   ...." );
		
		try {
			thread.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		System.out.println("... 6   ...." );
	}
}

执行结果:

... 1   ....
... 2   ....
... 3   ....
... 4   ....
... 5   ....
... 6   ....


如果没有加join 执行的结果可能就不是这个顺序了



你可能感兴趣的:(多线程)