JAVA基础---多线程2

线程间通讯:多个线程在处理同一资源,但是任务却不同

示例:ResourceDemo1

//资源
class Resource
{
	String name;
	String sex;
}
//输出
class Output implements Runnable
{
	Resource r;
	Output(Resource r)
	{
		this.r=r;
	}
	public void run()
	{
		while(true)
		{
			System.out.println(r.name+"......"+r.sex);
		}
	}
}
//输入
class Input implements Runnable
{
	Resource r;
	Input(Resource r)
	{
		this.r=r;
	}
	public void run()
	{
		int n=0;
		while(true)
		{
			if(n==0){
				r.name="Wnlife";
				r.sex="man";
			}else{
				r.name="孙艺珍";
				r.sex="女";
			}
			n=(n+1)%2;
		}
	}
}

class ResourceDemo1 
{
	public static void main(String[] args) 
	{
		//创建资源
		Resource r=new Resource();
		//创建线程任务
		Input a=new Input(r);
		Output b=new Output(r);
		//创建线程对象
		Thread t1=new Thread(a);
		Thread t2=new Thread(b);
		//开启线程
		t1.start();
		t2.start();
	}
}

如p2所示,出现了妖怪,因为线程不同步,出现了线程安全问题如p2所示,当Wnlife和man赋值给Resource后,孙艺珍幅值给name,sex还没等到赋值,Output线程抢占资源,所以出现了妖。解决方法,同步。

同步方式1:

//资源
class Resource
{
	String name;
	String sex;
}
//输出
class Output implements Runnable
{
	Resource r;
	Output(Resource r)
	{
		this.r=r;
	}
	public void run()
	{
		while(true)
		{
			synchronized(r){
			System.out.println(r.name+"......"+r.sex);
			}
		}
	}
}
//输入
class Input implements Runnable
{
	Resource r;
	Input(Resource r)
	{
		this.r=r;
	}
	public void run()
	{
		int n=0;
		while(true)
		{
			synchronized(r){
				if(n==0){
					r.name="Wnlife";
					r.sex="man";
				}else{
					r.name="孙艺珍";
					r.sex="女";
				}
			}
			n=(n+1)%2;
		}
	}
}

class ResourceDemo2 
{
	public static void main(String[] args) 
	{
		//创建资源
		Resource r=new Resource();
		//创建线程任务
		Input a=new Input(r);
		Output b=new Output(r);
		//创建线程对象
		Thread t1=new Thread(a);
		Thread t2=new Thread(b);
		//开启线程
		t1.start();
		t2.start();
	}
}

问题:如图3,连续的单个值,出现了覆盖,解决方法,给资源加入标记

同步方式2:等待/唤醒机制。 

涉及的方法:

1,wait(): 让线程处于冻结状态,被wait的线程会被存储到线程池中。
2,notify():唤醒线程池中一个线程(任意).
3,notifyAll():唤醒线程池中的所有线程。

这些方法都必须定义在同步中。因为这些方法是用于操作线程状态的方法。必须要明确到底操作的是哪个锁上的线程。

为什么操作线程的方法wait notify notifyAll定义在了Object类中? 

因为这些方法是监视器的方法。监视器其实就是锁。锁可以是任意的对象,任意的对象调用的方式一定定义在Object类中。

//资源
class Resource
{
	String name;
	String sex;
	boolean flag;
}
//输出
class Output implements Runnable
{
	Resource r;
	Output(Resource r)
	{
		this.r=r;
	}
	public void run()
	{
		while(true)
		{
			synchronized(r){
				if(!r.flag)try{r.wait();}catch(InterruptedException e){}
				System.out.println(r.name+"......"+r.sex);
				r.flag=false;
				r.notify();
			}
		}
	}
}
//输入
class Input implements Runnable
{
	Resource r;
	Input(Resource r)
	{
		this.r=r;
	}
	public void run()
	{
		int n=0;
		while(true)
		{
			synchronized(r){
				if(r.flag)try{r.wait();}catch(InterruptedException e){}
				if(n==0){
					r.name="Wnlife";
					r.sex="man";
				}else{
					r.name="孙艺珍";
					r.sex="女";
				}
				r.flag=true;
				r.notify();
			}
			n=(n+1)%2;
		}
	}
}

class ResourceDemo3
{
	public static void main(String[] args) 
	{
		//创建资源
		Resource r=new Resource();
		//创建线程任务
		Input a=new Input(r);
		Output b=new Output(r);
		//创建线程对象
		Thread t1=new Thread(a);
		Thread t2=new Thread(b);
		//开启线程
		t1.start();
		t2.start();
	}
}

改进代码:

//资源
class Resource
{
	private String name;
	private String sex;
	private boolean flag=false;
	public synchronized void set(String name,String sex){
		if(this.flag)try{this.wait();}catch(InterruptedException 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(name+"......"+sex);
		flag=false;
		this.notify();
	}
}
//输出
class Output implements Runnable
{
	Resource r;
	Output(Resource r)
	{
		this.r=r;
	}
	public void run()
	{
		while(true)
		{
			r.out();
		}
	}
}
//输入
class Input implements Runnable
{
	Resource r;
	Input(Resource r)
	{
		this.r=r;
	}
	public void run()
	{
		int n=0;
		while(true)
		{
			if(n==0){
				r.set("Wnlife","man");
			}else{
				r.set("孙艺珍","女");
			}
			n=(n+1)%2;
		}
	}
}

class ResourceDemo4
{
	public static void main(String[] args) 
	{
		//创建资源
		Resource r=new Resource();
		//创建线程任务
		Input a=new Input(r);
		Output b=new Output(r);
		//创建线程对象
		Thread t1=new Thread(a);
		Thread t2=new Thread(b);
		//开启线程
		t1.start();
		t2.start();
	}
}

生产者消费者问题:

Demo1:出现了线程安全问题

t0先挂,t1也挂了,t2活了,消费了烤鸭1,唤醒t0,t2挂了,
t3也等待了,t0活了生产了烤鸭2,唤醒了t1,生产了烤鸭3

class Resource
{
	private String name;
	private int count=1;
	private boolean flag=false;
	public synchronized void set(String name){
		if(flag)
			try{this.wait();}catch(InterruptedException e){}//   t0    t1
		this.name=name+count;//烤鸭1
		count++;
		System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);//生产烤鸭1 生产烤鸭2 生产烤鸭3
		flag = true;
		notify();
	}
	public synchronized void out(){
		if(!flag)
			try{this.wait();}catch(InterruptedException e){}//   t2    t3
		System.out.println(Thread.currentThread().getName()+"...消费者........"+this.name);//消费烤鸭1
		flag = false;
		notify();
	}
}

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

class  ProductConsumerDemo1
{
	public static void main(String[] args) 
	{
		Resource r = new Resource();
		Producer pro = new Producer(r);
		Consumer con = new Consumer(r);

		Thread t0 = new Thread(pro);
		Thread t1 = new Thread(pro);
		Thread t2 = new Thread(con);
		Thread t3 = new Thread(con);
		t0.start();
		t1.start();
		t2.start();
		t3.start();
	}
}

解决方法

生产者,消费者。

多生产者,多消费者的问题。
if判断标记,只有一次,会导致不该运行的线程运行了。出现了数据错误的情况。
while判断标记,解决了线程获取执行权后,是否要运行!

notify:只能唤醒一个线程,如果本方唤醒了本方,没有意义。而且while判断标记+notify会导致死锁。
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){}//   t1    t0
		
		this.name = name + count;//烤鸭1  烤鸭2  烤鸭3
		count++;//2 3 4
		System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);//生产烤鸭1 生产烤鸭2 生产烤鸭3
		flag = true;
		notifyAll();
	}

	public synchronized void out()//  t3
	{
		while(!flag)
			try{this.wait();}catch(InterruptedException e){}	//t2  t3
		System.out.println(Thread.currentThread().getName()+"...消费者........"+this.name);//消费烤鸭1
		flag = false;
		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();
		}
	}
}

class  ProducerConsumerDemo
{
	public static void main(String[] args) 
	{
		Resource r = new Resource();
		Producer pro = new Producer(r);
		Consumer con = new Consumer(r);

		Thread t0 = new Thread(pro);
		Thread t1 = new Thread(pro);
		Thread t2 = new Thread(con);
		Thread t3 = new Thread(con);
		t0.start();
		t1.start();
		t2.start();
		t3.start();
	}
}

 

jdk1.5新特性:

jdk1.5以后将同步和锁封装成了对象。 并将操作锁的隐式方式定义到了该对象中,将隐式动作变成了显示动作。

Lock接口: 出现替代了同步代码块或者同步函数。将同步的隐式锁操作变成现实锁操作。同时更为灵活。可以一个锁上加上多组监视器。

  • lock():获取锁。
  • unlock():释放锁,通常需要定义finally代码块中

Condition接口:出现替代了Object中的wait notify notifyAll方法。将这些监视器方法单独进行了封装,变成Condition监视器对象。可以和任意锁进行组合。

  • await();
  • signal();
  • signalAll();

Condition接口:出现替代了Object中的wait notify notifyAll方法。
        将这些监视器方法单独进行了封装,变成Condition监视器对象。
        可以任意锁进行组合。

import java.util.concurrent.locks.*;

class Resource
{
	private String name;
	private int count = 1;
	private boolean flag = false;

//	创建一个锁对象。
	Lock lock = new ReentrantLock();

	//通过已有的锁获取该锁上的监视器对象。
//	Condition con = lock.newCondition();

	//通过已有的锁获取两组监视器,一组监视生产者,一组监视消费者。
	Condition producer_con = lock.newCondition();
	Condition consumer_con = lock.newCondition();

	
	public  void set(String name)//  t0 t1
	{
		lock.lock();
		try
		{
			while(flag)
//			try{lock.wait();}catch(InterruptedException e){}//   t1    t0
			try{producer_con.await();}catch(InterruptedException e){}//   t1    t0
		
			this.name = name + count;//烤鸭1  烤鸭2  烤鸭3
			count++;//2 3 4
			System.out.println(Thread.currentThread().getName()+"...生产者5.0..."+this.name);//生产烤鸭1 生产烤鸭2 生产烤鸭3
			flag = true;
//			notifyAll();
//			con.signalAll();
			consumer_con.signal();
		}
		finally
		{
			lock.unlock();
		}
		
	}

	public  void out()// t2 t3
	{
		lock.lock();
		try
		{
			while(!flag)
//			try{this.wait();}catch(InterruptedException e){}	//t2  t3
			try{cousumer_con.await();}catch(InterruptedException e){}	//t2  t3
			System.out.println(Thread.currentThread().getName()+"...消费者.5.0......."+this.name);//消费烤鸭1
			flag = false;
//			notifyAll();
//			con.signalAll();
			producer_con.signal();
		}
		finally
		{
			lock.unlock();
		}
		
	}
}

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



class  ProducerConsumerDemo2
{
	public static void main(String[] args) 
	{
		Resource r = new Resource();
		Producer pro = new Producer(r);
		Consumer con = new Consumer(r);

		Thread t0 = new Thread(pro);
		Thread t1 = new Thread(pro);
		Thread t2 = new Thread(con);
		Thread t3 = new Thread(con);
		t0.start();
		t1.start();
		t2.start();
		t3.start();

	}
}

wait 和 sleep 区别?

1,wait可以指定时间也可以不指定。
   sleep必须指定时间。

2,在同步中时,对cpu的执行权和锁的处理不同。
    wait:释放执行权,释放锁。
    sleep:释放执行权,不释放锁。

同步中只有一个正在运行的线程。

停止线程:
 

1.定义循环结束标记

因为线程任务一般都是循环,只要控制住了循环即可。

2.使用interrupt方法

该方法是结束线程的冻结状态,使线程回到运行状态中来。


1,stop方法。(过时)

2,run方法结束。

怎么控制线程的任务结束呢?
任务中都会有循环结构,只要控制住循环就可以结束任务。

控制循环通常就用定义标记来完成。

但是如果线程处于了冻结状态 ,无法读取标记。如何结束呢?

可以使用interrupt()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备cpu的执行资格。 

当时强制动作会发生了InterruptedException,记得要处理

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

class StopThreadDemo 
{
	public static void main(String[] args) 
	{
		StopThread st = new StopThread();

		Thread t1 = new Thread(st);
		Thread t2 = new Thread(st);

		t1.start();
		t2.setDaemon(true);//t2设置为守护线程
		t2.start();


		int num = 1;
		for(;;)
		{
			if(++num==50)
			{
//				st.setFlag();
				t1.interrupt();
//				t2.interrupt();
				break;
			}
			System.out.println("main...."+num);
		}

		System.out.println("over");
	}
}

join方法:

class Demo implements Runnable
{
	public void run()
	{
		for(int x=0; x<50; x++)
		{
			System.out.println(Thread.currentThread().toString()+"....."+x);
			Thread.yield();
		}
	}
}

class  JoinDemo
{
	public static void main(String[] args) throws Exception
	{
		Demo d = new Demo();

		Thread t1 = new Thread(d);
		Thread t2 = new Thread(d);

		t1.start();


		t2.start();
//		t2.setPriority(Thread.MAX_PRIORITY);

//		t1.join();//t1线程要申请加入进来,运行。临时加入一个线程运算时可以使用join方法。

		for(int x=0; x<50; x++)
		{
//			System.out.println(Thread.currentThread()+"....."+x);
		}
	}
}

多线程面试题:

class Test implements Runnable //第一行会报错,因为没有覆盖接口方法
{
	public void run(Thread t)
	{}
}
 
class ThreadTest 
{
	public static void main(String[] args)
	{
		new Thread(new Runnable()
		{
			public void run()
			{
				System.out.println("runnable");//次运行
			}
		})
		{
			public void run()
			{
				System.out.println("subThread run");//优先运行
 
			}
		}.start();
	}
}

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值