黑马程序员——多线程

本文详细介绍了Java多线程的基本概念、实现方式、线程间的协作与控制,包括线程与进程的区别、并行与并发的概念、多线程的实现方法(如继承Thread类与实现Runnable接口)、线程生命周期、线程的优先级与控制方法,以及多线程可能遇到的异常情况。通过实例演示了如何使用多线程解决实际问题。

 ------- android培训java培训、期待与您交流! ----------

多线程

一、线程与进程
计算机中正在运行的程序就是一个进程,系统进行资源分配和调用的独立单位,每一个进程都有他自己的内存空间和系统资源。
进程中负责执行代码功能的就是一个线程。

举例:QQ是一个进程,QQ中视频聊天的同时,还可以打字,这就是多线程。

二、多线程
并行和并发:
并行是逻辑上同时运行多个程序。
并发是物理上同时运行多个程序。
有利:
1、让我们可以同时干多件事情。
2、提高CPU的利用率
有弊:
1、存在了线程安全问题
2、更多的线程,增加了CPU得负担
3、降低了线程的执行概率
4、引发了死锁现象

JVM执行程序时是多线程还是单线程呢?
是多线程,最少同时存在主线程和垃圾回收器线程。

三、多线程的实现
两种方法来实现多线程:
1、继承Thread类,重些run()方法
2、实现Runnable接口

继承Thread类来实现多线程演示:
package it.heima.thread;

public class SaltTicketDemo {
	public static void main(String[] args) {
		Employee employee1=new Employee("窗口1");
		Employee employee2=new Employee("窗口2");
		Employee employee3=new Employee("窗口3");
		//employee1.run();
		//employee1start();.
		employee1.start();
		employee2.start();
		employee3.start();
	}
}

class Employee extends Thread{
	static int tickets=100;
	String name;
	public Employee(String name){
		this.name=name;
	}
	public void saltTicket(){
		while(tickets>0){
			System.out.println(name+"卖了第"+tickets--+"张票");
		}
	}
	@Override
	public void run() {
		saltTicket();
		//super.run();
	}

	
}
run()和start()的区别?
调用run()只是调用一个普通的封装方法。
调用start()是先启动了线程,然后JVM通过该线程去调用run()。

多线程存在的异常:
IllegalThreadException:非法状态异常
因为同一个线程调用了两次

四、多线程的方法
线程的名字:
String getName()-----获取线程的名字
Thread的无参构造会调用init(null,null,"Thread-"+nextThreadNum(),0)给线程赋予名字Thread-0/1/2....
init()会将name转成字符数组存到char[] name成员变量中去。
0、1、2是通过nextInitNumber()控制的。该方法返回一个自增的int类型值。
Thread方法的名字变量是char[] name;通过getName()可以调用ValueOf装换成字符串输出。
void setName(String s)-----设置线程名字

线程的优先级:
线程的调度模型:
1、分时调度模型 2、抢占式调度模型
JAVA采用了抢占式调度模型。
线程的优先级:优先级高的线程能执行更多的时间
优先级的大小是一个1-10的int类型数据。
getPriority()----获得线程的优先级
返回一个Int类型,默认优先级是5.
setPriority(int num)-----设置优先级
注意:当你传入大于10的数时,有IlleagelArgumentException 非法参数异常
线程的优先级仅仅表示了获取CPU执行权的概率,并不是一定先执行。

线程的控制:
public static void sleep(long millis)-----线程休眠
public final void join()-----线程加入
public static void yeild()------线程礼让
public final void setDaemon(boolean on)-----后台线程
public final void stop()-----线程中断
public void interrupt()-------线程中断
线程方法的演示:
package it.heima.thread;

import java.util.Date;

import javax.swing.plaf.SliderUI;

public class ThreadMethodDemo {

	public static void main(String[] args) throws InterruptedException {
		Demo demo1=new Demo();
		Demo demo2=new Demo();
		Demo demo3=new Demo();
		
		demo1.setName("张三");
		demo2.setName("李四");
		demo3.setName("王五");
		/*demo1.setDaemon(true);
		demo2.setDaemon(true);
		demo3.setDaemon(true);*/
		
		demo1.start();
		//demo1.setPriority(9);
		/*try {
			demo1.join();	//加入线程,demo1执行完再执行demo2和demo3
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}*/
		//demo2.start();
		//demo3.start();
		Thread.currentThread().setName("小头爸爸");
		for(int i=0;i<10;i++){
			System.out.println(Thread.currentThread().getName()+":"+i);
		}
		Thread.sleep(3000);
		demo1.interrupt();
	}

}

class Demo extends Thread{

	@Override
	public void run() {
		System.out.println(getName()+"线程开始"+new Date());
		//for(int i=0;i<100;i++){
		//	System.out.println(getName()+" "+i);
			//Thread的run()没有异常,子类也不能抛异常,只能try-catch
			try {
				sleep(10000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				System.out.println(getName()+"线程被终止了");
			}
			//yield();//礼让线程,让多个线程的执行更平均,但不能保证
			System.out.println(getName()+"线程结束"+new Date());
		//}
	}
	
}

线程的生命周期图:


第二种实现多线程的方法:
实现Runnable接口,重写run()方法
步骤:
1、创建MyRunnable实现run()
2、创建MyRunnable对象
3、创建Thread对象,并传入MyRunnable对象
4、Thread对象调用run方法
package day25_thread;

public class ThreadDemo {
	public static void main(String[] args) {
		Sale s = new Sale();
		
		Thread thread1 = new Thread(s, "窗口一");
		Thread thread2 = new Thread(s, "窗口二");
		Thread thread3 = new Thread(s, "窗口三");

		thread1.start();
		thread2.start();
		thread3.start();
		
	}
}

class Sale implements Runnable {
	Object o=new Object();
	int count = 100;

	@Override
	public void run() {
		while (true) {
			synchronized (o) {
				if (count >= 0) {
					System.out.println(Thread.currentThread().getName() + "卖了第" + (100 - count) + "张票");
					count--;
					
				} else {
					System.out.println("票已售罄");
					break;
				}

			}
	
		}
		
	}

}

为什么调用star()t方法会启动我们重写的run()?
因为Thread 里维护了一个Runnable对象target,通过构造函数可以把我们自己写的线程类的对象传入并复制给target,如果target不为null,就会调用target.run()。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值