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