黑马程序员 Java基础知识总结-多线程
来源:互联网 发布:砸金蛋程序源码 编辑:程序博客网 时间:2024/05/23 01:15
一、进程与线程的区别:
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();}}
上述代码执行的结果为:
- 黑马程序员 Java基础知识总结-多线程
- 黑马程序员--JAVA基础知识--多线程
- 黑马程序员------java基础知识总结
- 黑马程序员---java基础知识总结
- java基础知识总结---黑马程序员
- 黑马程序员--Java基础知识总结
- 黑马程序员-Java基础知识总结
- 黑马程序员--Java基础知识总结
- 黑马程序员_JavaSE基础知识总结十四:多线程
- 黑马程序员:java基础知识(多线程)
- 黑马程序员,Java基础知识六:多线程
- 黑马程序员---java基础知识(四):多线程
- 黑马程序员 Java多线程总结
- 黑马程序员---java多线程总结
- 黑马程序员-----java多线程总结*
- 黑马程序员---------java多线程总结
- 黑马程序员 java多线程总结
- 黑马程序员--多线程基础知识
- 第四章 多视图应用
- Qmake 多文件编译 在项目中的使用
- 相关子查询(correlated subquery) 与非相关子查询
- 【编程好习惯】使用空格增加可读性
- css 使用技巧
- 黑马程序员 Java基础知识总结-多线程
- Android通过HTTP协议实现多线程下载
- uitextField 设置边框颜色
- PN结
- hdu4279 找规律+小想法
- Android 编程下的代码混淆
- C++ Primer---- 奇怪的 protected 成员
- pat 1065
- 四周 项目4 扩展2 文件与工资操作