首页 > 编程 > Java > 正文

java多线程的认识

2019-11-08 01:32:53
字体:
来源:转载
供稿:网友

一个进程里面有多个线程在执行,每个线程通过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));这个就是线程池当中的一个的使用了,就不详细介绍了。。。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表