黑马程序员-----java多线程总结*

原创 2013年12月03日 22:39:00

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------



一、多线程

调用run方法的对象必须是Runnable的子类对象,

第一种:继承Thread类,因为Thread类也实现了Runnable接口

第二种:实现Runnable接口,因为Runnable接口中没有start方法,所以要把该接口类对象引用作为参数传递给Thread类的构造方法

1、线程控制着进程的执行

2、一个线程又称为一个控制单元

3、JVM启动的时候,会产生一个java.exe进程也之对应

4、java.exe进程在运行过程中至少有一个线程负责java程序的执行,该线程叫做主线程

5、JVM启动之后,java.exe进程启动会有两个线程执行,一个是主线程,一个是垃圾回收机制

为什么需要垃圾回收机制?

因为如果没有垃圾回收机制,那么当主函数里的垃圾对象堆积到一定程度后,程序会停下来对垃圾进行回收处理,这样给用户的感觉就是程序运行一段时间又停一段时间,然后又运行。


线程和进程和OS(操作系统)的关系?

1、线程存在与进程中,OS先创建了进程,然后再创建线程

2、线程是JVM调用底层操作系统的功能来创建的

总结:进程和线程都是由OS创建的,JVM只是起了调用OS的功能而已!


创建新执行线程有两种方法。

第一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。

步骤:

1、继承Thread类,创建Thread类的子类

2、该子类复写Thread类的run方法

复写run方法注意事项:因为Thread类中的run方法没有抛出异常,所以子类中的run方法如果出现异常能够内部处理不能够抛

3、创建子类对象(相当于创建了线程),调用start方法

注意:

start方法的作用:一是启动了线程;二是调用了run方法


为什么会交替打印?

因为CPU是单核,此时程序中存在两个控制单元/线程,CPU要进行快速的切换动作

为什么每次打印的结果都不一样?

因为线程在运行的过程中,是在抢夺CPU的执行权,谁抢到了执行权就运行该线程。

为什么要复写run方法?

为了将自定义代码存放在run方法中,让线程运行指定内容

为什么非要调用start方法?

因为只有当调用start方法后,start方法的本地native方法和start0方法才会调用操作系统的底层资源创建开启线程

调用start方法后会立马执行该线程吗?

不一定!因为CPU在某一个时刻只会执行一个线程,其余线程都处于临时堵塞状态,都在等待执行权


线程从运行到消亡的过程:

start()方法:当调用了start方法后,线程不一定马上执行,很大可能会跳转到临时堵塞状态,只有很小的几率跳到运行状态

sleep(时间)方法和wait()方法:当调用了这两个方法后,线程会跳转到冻结状态,并放弃CPU的执行权

notify()方法(或者是sleep方法的时间结束):当调用了该方法后,冻结状态的线程会被激活,很大可能会跳转到临时堵塞状态,只有很小的几率跳到运行状态

stop()方法(或者是run方法运行完):当掉用了该方法后,线程会由运行状态走到消亡状态


决定线程是临时堵塞状态还是运行状态的因素是:看该线程是否拥有CPU执行权,有就运行,没有就堵塞


 

是否具有CPU执行资格

是否具有CPU执行权

 运行状态【双有】

冻结状态【双无】

----

临时阻塞状态【一有一无】




第二种方法是声明实现 Runnable 接口的类。该类然后实现run 方法。然后可以分配该类的实例,在创建 Thread时作为一个参数来传递并启动。


实现Runnable接口相对于继承Thread类来说,有如下的显著优势:
   1.适合多个相同代码的线程去处理同一个资源的情况
   2.可以避免由于java的单继承特性带来的局限
   3.增强了程序的健壮性,代码能够被多个线程共享,代码与数据是独立的




多线程安全问题:
实现Runnable接口可以让多线程访问同一资源,但是当某一线程处理共享区数据到一半时执行权别另一线程抢走了,就可能导致数据错误,为了避免出现这种情况,java引进了解决办法,就是同步代码块。原理是当某个线程在操作共享区数据时,其他线程不能够操作,只能够等该线程操作完毕才可以操作共享数据

代码:synchronized(对象){共享代码块},其中对象可以为任意,注意:要有设计到共享数据的运算才放在synchronize块里


同步代码块和同步函数的区别:

1、同步代码块的锁是任意对象;同步函数的锁是this

开发一般都用同步代码块!



多线程通信:

多线程通信就是多个线程在操作同一个资源,例子:一个线程往仓库里存东西,另一个线程从仓库取东西

多线程出现问题原因:

1、不是同一个锁

2、没有同步两个或两个以上的线程


多线程通信存在的问题:

加入这时候的需求是:仓库里只能够保持一件东西,这样的话就不可以了

这时候用到等待唤醒机制!




多线程等待唤醒机制:

分析:虽然一个线程往仓库存东西的时候另一个线程不能够取,但是要保证仓库里只能有一件物品,就需要用到wait()、notify()、notify()方法了

思路:首先判断,仓库里有没有东西,如果没有,则一个线程往里面存东西,这个过程通过锁来判断。当存完东西以后改变锁的状态,并且唤醒另一个线程从仓库中取出东西

为什么要用while不用if来判断是否等待?

因为如果有两个线程都在等待,Allnotify()后,用if的话第一线程往里面存入一个东西,改变锁的状态,但是第二个线程不会去判断锁的状态,继续往里面存入一个东西,造成错误;而while语句的特点是被唤醒以后会先又去判断条件是否满足

为什么要用Allnotify方法?

因为如果当有很多线程时,用notify方法,会唤醒存入线程而不唤醒取出线程,这样的话造成线程全部等待

经典例子:

public class Produce_Consume {
	public static void main(String[] args) {

	Resource r = new Resource();
	
	Produce p = new Produce(r);   //为了保证r对象是同一个
	Consume c = new Consume(r);	  //为了保证r对象是同一个
	
	Thread t1 = new Thread(p);
	Thread t2 = new Thread(p);
	Thread t3 = new Thread(c);
	Thread t4 = new Thread(c);
	
	t1.start();
	t2.start();
	t3.start();
	t4.start();
	
	}
}

//共享资源
class Resource{
	private String name;  //商品名称
	private	int count=1;   //计数
	private boolean flag= false;
	
	//生产
	public synchronized void intPut(String name){
		while(flag){
			try{
				wait();
			}catch(Exception e){
				
			}
		}
		this.name = name;
		count++;
		System.out.println(Thread.currentThread().getName()+this.name+this.count);
		flag=true;
		this.notifyAll();
	}
	
	//消费
	public synchronized void OutPut(){
		while(!flag){
			try{
				wait();
			}catch(Exception e){
				
			}
		}
		System.out.println(Thread.currentThread().getName()+this.name+this.count+"...............");
		flag=false;
		this.notifyAll();
	}
}

//生产者
class Produce implements Runnable{
	private Resource r;
	Produce(Resource r){
		this.r = r;
	}
	public void run(){
		while(true){
//			
				r.intPut("面包");
		}
	}
}

//消费者
class Consume implements Runnable{
	private Resource r;
	Consume(Resource r){
		this.r = r;
	}
	
	public void run(){
		while(true){
			
				r.OutPut();
			
		}
	}
		
}



JDK 1.5以后,Lock替代了synchronized,Condiation替代了监视器方法(其中await替代了wait,signal替代了notify,signalAll替代了notifyAll)

好处在于:如果notifyAll的话,会唤醒本方线程,太浪费资源,但是用signal的话可以选择性的唤醒对方线程

import java.util.*;

public class Produce_Consume {
	public static void main(String[] args) {

		Resource r = new Resource();

		Produce p = new Produce(r); // 为了保证r对象是同一个
		Consume c = new Consume(r); // 为了保证r对象是同一个

		Thread t1 = new Thread(p);
		Thread t2 = new Thread(p);
		Thread t3 = new Thread(c);
		Thread t4 = new Thread(c);

		t1.start();
		t2.start();
		t3.start();
		t4.start();

	}
}

// 共享资源
class Resource {
	private String name; // 商品名称
	private int count = 1; // 计数
	private boolean flag = false;

	private Lock lock = new ReentrantLock();
	// 创建生产者condition方法
	private Condition condition_pro = lock.newCondition();

	// 创建消费者condition方法
	private Condition condition_con = lock.newCondition();

	// 生产
	public void intPut(String name) throws InterruptedException {
		lock.lock();

		
			try {
				while (flag) {
					condition_pro.await();
				}
				this.name = name;
				count++;
				System.out.println(Thread.currentThread().getName() + this.name
						+ this.count);
				flag = true;
				condition_con.signal();
			} finally {
				lock.unlock();
			}
	}

	// 消费
	public void OutPut() throws InterruptedException {
		lock.lock();	
			try {
				while (!flag) {
					condition_con.await();
				}
				System.out.println(Thread.currentThread().getName() + this.name
						+ this.count + "...............");
				flag = false;
				condition_pro.signal();
			} finally {
				lock.unlock();
			}

	}
}

// 生产者
class Produce implements Runnable {
	private Resource r;

	Produce(Resource r) {
		this.r = r;
	}

	public void run() {
		while (true) {
			try {
				r.intPut("面包");
			} catch (Exception e) {

			}
		}
	}
}

// 消费者
class Consume implements Runnable {
	private Resource r;

	Consume(Resource r) {
		this.r = r;
	}

	public void run() {
		while (true) {

			try {
				r.OutPut();
			} catch (Exception e) {

			}

		}
	}

}




---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

详细请查看:http://edu.csdn.net

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

黑马程序员《java基础总结(六)》(多线程)

---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------  多线程: 进程:正在进...

黑马程序员学习笔记 Java中多线程与并发的总结

1.      计算机系统 使用高速缓存来作为内存与处理器之间的缓冲,将运算需要用到的数据复制到缓存中,让计算能快速进行;当运算结束后再从缓存同步回内存之中,这样处理器就无需等待缓慢的内存读写了。 ...

黑马程序员_java_多线程总结(上)

------- android培训、java培训、期待与您交流! ---------- 多线程总结 多线程就是指一个应用程序中有多条并发执行的线索,每条线索都被称作一个线程,它们会交替执行...

黑马程序员--Java 多线程与并发总结

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------       今天重新复习了《Java编程思想》中的第21章 并发及张孝祥_Java多线程视频教...

黑马程序员--Java学习日记之总结复习(多线程和设计模式)

一.线程实现方式:  1.继承Thread类;  2.实现Runnable接口; 二.设置获取线程的名称:  getName()和setName(String name); 三.设置获取线程的优先级:...

黑马程序员---------java多线程总结

学习新技术: 1、该技术是什么; 2、该技术的特点,注意事项; 3、该技术怎么使用; 4、该技术在哪里使用; 解决一个具体问题: 1、明确需求;要做什么 2、分析思路;怎么做 3、确定...

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

---------------------- ASP.Net+Android+IOS">http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发...

黑马程序员_java多线程的一些总结(一)

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ------- 一、    进程和线程 1、   进程和线程的关系。 一般来说,我们运行一个应用程序的,就启动...

黑马程序员_java_多线程总结(下)

------- android培训、java培训、期待与您交流! ---------- (1)问题产生原理分析      注意:每个线程有个普通的成员变量Student,创建线程的...

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

黑马程序员:Java基础总结 多线程  ASP.Net+Android+IO开发、.Net培训、期待与您交流! ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)