java多线程的认识

一个进程里面有多个线程在执行,每个线程通过cpu的算法,并行的执行。所以,对于同一资源来说,就可能存在安全性的问题了,有可能出现数据不同步的情况。在java里面多线程并发的问题,也是非常需要注意的。今天就来讲讲多线程的问题。

在java里面写一个线程很简单,只要继承一个Thread 类或者 实现一个Runnable 接口就能实现一个线程了。由于java里面,一个类只允许有一个父类,所以通过继承Thread 就有缺陷了,不能实现类中的数据共享,而Runnable确实可以的。像常见的卖票的例子,就说明这点了。

通过继承Thread 的方式实现线程的话,是这样的 


public class ExtendsThread extends Thread{
	private int tickert=10;
	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.run();
		for(int i=0;i<10;i++){
			System.out.println("卖票:ticket"+this.tickert);
		}
	}
}
public static void main(String[] args) {
		ExtendsThread et=new ExtendsThread();
		ExtendsThread et2=new ExtendsThread();
		ExtendsThread et3=new ExtendsThread();
		et.start();
		et2.start();
		et3.start();
	}
会发现总共买了30张票,而我们定义的ticket为10张票,这就是Thread的缺陷了,其实也不能说是缺陷,因为是三个不同的对象了,所以才会这样,但是如果是Runnable的话,就相当于是一个对象,如下:

public class ImplementRunnable implements Runnable{

	private int ticket=10;
	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i=0;i<10;i++){
			if(this.ticket>0){
				System.out.println("卖票:ticket"+this.ticket--);
			}
		}
	}

}
public class TicketThread {


	public static void main(String[] args) {
		ImplementRunnable et=new ImplementRunnable();
		new Thread(et).start();
		new Thread(et).start();
		new Thread(et).start();
	}
	
}
继承这个Runnable接口,就不会像之前那样的结果了。这个只是Thread 和Runnable的区别。

在java多线程并发的情况下,我们需要考虑数据同步的问题,以及线程池的使用,来减少开多个线程耗费的资源问题。

在线程里面有两个方法简要说下,onStop() 和 onInterrupt() 。onStop()方法会让线程突然停止,导致数据上的丢失,这个方法也已经被java抛弃了。

onInterrupt()方法,可以实现线程的退出,但是需要正确的使用。这个方式是在线程阻塞的情况下,会接收到一个中断异常(InterruptException),像wati()或者sleep()的时候,可以调用此方法。但是,也不可直接调用,需要设置共享变量来判断是否正确的退出线程。


对于同一资源,如果有多个线程想要对其操作,那么必然会发生资源抢占的问题,如果处理不当,将会出现数据紊乱的状况。这个时候就需要考虑同步跟互斥了。就是同一时间只能有一个线程访问,其他线程需要进入等待状态,访问完成之后,再唤醒所有在等待中的线程,然后,再互相竞争资源。

synchronized 是一个同步关键字,使用了这个关键字,可以将资源锁起来,不给其他线程访问,进入等待状态。等到这个线程完成之后,会调用wati()方法,代表此线程进入等待状态。然后再调用notify()或者notifyAll()方法来唤醒线程。notify()是唤醒一个线程来访问,notifyAll()方法是唤醒所有的线程来访问。

public class Resource {

	private boolean flag;
	private int count=0;
	
	public synchronized void create(){
		while(flag){  //这个标记表示生产完成,要进入等待状态
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		count++;
		System.out.println(Thread.currentThread().getName()+"生产者----"+count);
		flag=true;
		notifyAll(); //这里需要调用此方法,防止,notify()会调用到本线程,导致死锁
	}
	public synchronized void consume(){
		while(!flag){ //代表消费过了就进入等待状态
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println(Thread.currentThread().getName()+"消费者----"+count);
		flag=false;
		notifyAll();
	}
}
这段代码代表的是,资源。里面的代码解释都有备注。

public class Producer implements Runnable{
	Resource resource;
	public Producer(Resource resource){
		this.resource=resource;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true){
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			resource.create();
		}
		
	}

}
这个是生产的线程。

public class Customer implements Runnable{
	
	Resource resource;
	public Customer(Resource resource){
		this.resource=resource;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true){
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}	
			resource.consume();
		}
		
	}

}
这个是消费的线程。

public class ProducerCustomerTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Resource resource=new Resource();
		new Thread(new Producer(resource)).start();
		new Thread(new Producer(resource)).start();
		new Thread(new Customer(resource)).start();
		new Thread(new Customer(resource)).start();
	}

}
测试代码。

下面就是结果了。




从打印结果中可以看出,没有出现资源不准确的情况,这个就是简单的多线程协作的处理。

当然,在使用多个线程的时候,如果不使用线程池,将会带来很大的开销。其实,线程池的使用很简单。线程池的有点大家自行google.~

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
		cachedThreadPool.execute(new Producer(resource));
		cachedThreadPool.execute(new Producer(resource));
		cachedThreadPool.execute(new Customer(resource));
		cachedThreadPool.execute(new Customer(resource));
这个就是线程池当中的一个的使用了,就不详细介绍了。。。






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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值