黑马程序员——多线程

 ------- 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()。

黑马程序员多线程练习题主要包括两个问题。第一个问题是如何控制四个线程在打印log之前能够同时开始等待1秒钟。一种解决思路是在线程的run方法中调用parseLog方法,并使用Thread.sleep方法让线程等待1秒钟。另一种解决思路是使用线程池,将线程数量固定为4个,并将每个调用parseLog方法的语句封装为一个Runnable对象,然后提交到线程池中。这样可以实现一秒钟打印4行日志,4秒钟打印16条日志的需求。 第二个问题是如何修改代码,使得几个线程调用TestDo.doSome(key, value)方法时,如果传递进去的key相等(equals比较为true),则这几个线程应互斥排队输出结果。一种解决方法是使用synchronized关键字来实现线程的互斥排队输出。通过给TestDo.doSome方法添加synchronized关键字,可以确保同一时间只有一个线程能够执行该方法,从而实现线程的互斥输出。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [黑马程序员——多线程10:多线程相关练习](https://blog.csdn.net/axr1985lazy/article/details/48186039)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值