黑马程序员 Java基础知识总结-多线程

进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以有多个线程。

一、进程与线程的区别:

       1.进程有独立的进程空间,进程中的数据存放空间(堆空间和栈空间)是独立的。

       2.线程的堆空间是共享的,栈空间是独立的,线程消耗的资源也比进程小,相互之间可以影响的。

二、java中创建多线程的方式:1、继承Thread类;2、实现Runnable接口。

两种进程创建方式比较:

第二种创建多线程的方法:继承Thread类

   run()和start()方法的区别:
   创建多线程的一种方式,继承Thread类
   步骤:
    1、定义类并继承自Thread类
    2、覆写Thread类中的run()方法
    目的:将自定义的代码存储在run()方法中,让线程运行
    3、调用现成的start()方法
    目的:start()是启动线程用的

package com.blog.source;

public class ThreadDemo extends Thread{
	public void run(){
		for(int x = 0 ;x <100 ; x++)
			System.out.println(Thread.currentThread().getName()+"在运行");
	}
	public static void main(String[] args) {
		new ThreadDemo().start();
		new ThreadDemo().start();
		new ThreadDemo().start();
	}
}

继承Thread类这种实现多线程时,不能在继承其他的java类(因为java只能但集成),相同的资源也不能共享,下面看一下线程的第二种实现方式,实现Runnable接口

第二种创建多线程的方法:实现Runnable接口
   步骤:
    1、创建类并实现Runnable接口
    2、实现Runnable接口中的run方法
    3、通过Thread类建立线程对象
    4、将Runnable接口的子类作为实际参数传递给Thread的构造方法
    为什么要将Runnable接口的子类对象传递给Thread的构造方法?
    因为,自定对象所属Runnable接口的子类对象,所以要让线程去
    执行指定run方法中的代码,就必须明确该run方法所属对象。
    5、调用Thread类中的run方法,并调用Runnable接口中的run方法

package com.blog.source;

public class ThreadDemo implements Runnable{
	public void run(){
		for(int x = 0 ;x <100 ; x++)
			System.out.println(Thread.currentThread().getName()+"在运行");
	}
	public static void main(String[] args) {
		ThreadDemo td = new ThreadDemo();
		new Thread(td).start();
		new Thread(td).start();
		new Thread(td).start();
	}
}

实现Runnbale接口和继承Thread类有什么区别?

  实现方式,好处是避免了java中单继承的局限性,在实现多线程的时候建议
使用实现方式
  继承Thread类:线程代码存放在Thread子类run方法中
   实现Runnable:线程代码存放在接口子类的run方法中

三、线程的生命周期:

   新建状态,至今尚未启动的线程处于这种状态。
   运行状态,正在 Java 虚拟机中执行的线程处于这种状态。
   阻塞状态,受阻塞并等待某个监视器锁的线程处于这种状态。

四、控制线程:

控制线程是一件复杂的事情,java给我提供了控制线程的对象:
       join方法:调用join方法的线程对象强制运行,该线程强制运行期间,其他线程无法运行,必须等到该线程结束后其他线程才可以运行。

      sleep方法:线程休眠: 让执行的线程暂停一段时间,进入阻塞状态。

五、线程安全问题:当多条语句在操作同一数据时,当一个线程只执行了共享数据的一部分时,另外一个线程取得了执行权,修改共享数据。这种情况会导致数据修改错误。

    解决线程安全问题有三种办法,同步代码块(java中用synchronized关键字同步)、同步方法和静态方法的同步,在jdk1.5之后java引入了同步锁机制。

六、线程之间的通信:

   假设现在有一个容器,线程一和线程二都要使用这个容器,线程一使用这个容器的目的是往容器里面放东西,线程二使用这个容器里面取东西,容器里面有东西的时候线程一不能往里面放东西,容器为空的时候线程二不能从容器里面取出东西。此时只有线程一和线程二彼此通信才能知道容器里面是否有东西。

wait():让当前线程放弃监视器进入等待,直到其他线程调用同一个监视器并调用notify()或notifyAll()为止。

notify():唤醒在同一对象监听器中调用wait方法的第一个线程。

notifyAll():唤醒在同一对象监听器中调用wait方法的所有线程。

举例:生产者和消费者

生产者和消费者描述的是这样一个过程:生产者只能生产商品 ,消费者只能使用生产者生产出来的商品。此时,他们都会用到一个共同的区域,就是生产者将生产出来的产品放到这个区域,消费者将该区域内的产品取走 。在过程中会出现如果该区域内没有商品消费者则不能取,如果该区域内有商品生产者不能生产。

Resource.java描述的是生产者和消费者共同使用的资源区域 

public class Resource {
	/* 创建资源类 */
	private String reName;// 产品资源名称

	private int count = 0;// 交替生产,目的是为了好区分
	/* 如果flag为false时,生产者可以生产,此时消费者不能消费;若falg为ture则不能生产,消费者可以消费 */
	private boolean flag = false;

	public boolean isFlag() {
		return flag;
	}

	public void setFlag(boolean flag) {
		this.flag = flag;
	}

	public int getCount() {
		return count++;
	}

	public void setCount(int count) {
		this.count = count;
	}

	public String getReName() {
		return reName;
	}

	public void setReName(String reName) {
		this.reName = reName;
	}

}

Producer.java描述生产者:

public class Producer implements Runnable {
	/*创建一个生产者类实现Runnable接口,创建多线程*/
	private Resource r = null;
	
	public Producer(Resource r) {
		this.r = r;
	}
	//覆写run方法实现多线程
	public void run() {
		while (true) { //一直生产
			synchronized (r) {
				/*如果flag为真则表示产品存放区有产品,此时不能生产产品,所有生产者线程应该休眠等待*/
				while (r.isFlag()) {
					try {
						r.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				if (r.getCount() == 0) {
					r.setReName("苹果");
					System.out.println(Thread.currentThread().getName()+ "--生产一个--" + r.getReName());
				} else {
					r.setReName("梨子");
					System.out.println(Thread.currentThread().getName()+ "--生产一个--" + r.getReName());
				}
				r.setCount(r.getCount() % 2);
				/*当前线程创建一个产品之后产品区有了新产品,此时不能进行生产,更改标识flag,并唤醒其他线程*/
				r.setFlag(true);
				r.notifyAll();
			}
		}
	}
}

Consumer.java描述消费者

<pre name="code" class="java">public class Consumer implements Runnable {
	private Resource r = null;

	public Consumer(Resource r) {
		this.r = r;
	}

	public void run() {
		while (true) {
			synchronized (r) {
				/*如果flag为真,表示产品区有新产品,此时可以消费,反之则不能消费,所有消费者线程等待*/
				while (!r.isFlag()) {
					try {
						r.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				System.out.println(Thread.currentThread().getName() + "--吃掉--"+ r.getReName());
				/*当前线程将产品消费掉之后,更改标识,并唤醒其他线程*/
				r.setFlag(false);
				r.notifyAll();
			}
		}
	}

}

 

ProducerAndConsumer.java为程序的入口 ,创建多个生产者和多个消费者

public class ProducerAndConsumer {
	public static void main(String[] args) {
		 Resource r = new Resource();
		 //生产者线程
		 new Thread(new Producer(r)).start();
		 new Thread(new Producer(r)).start();
		 new Thread(new Producer(r)).start();
		 new Thread(new Producer(r)).start();
		 
		 //消费者线程
		 new Thread(new Consumer(r)).start();
		 new Thread(new Consumer(r)).start();
		 new Thread(new Consumer(r)).start();
		 new Thread(new Consumer(r)).start();
	}
}


上述代码执行的结果为:




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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值