1、线程
a 进程、线程都是实现并发机制的有效手段;
b 线程是比进程更小的执行单位,是在进程基础上的进一步划分;
c 一个程序运行,可能多个线程同时运行
例如,打开word是启动了一个系统进程,里面的拼写检查就是一个小的线程。
2、Thread类
Thread类属于java.lang.Object。在文档中的定义:public class Thread extends Object implements Runnable
可以看出,Thread类也实现了Runnable接口,一个类要继承thread类必须重写run()方法。
实例:
定义一个线程类MyThread实现Thread
public class MyThread extends Thread{
private String name;//再类中定义一个属性
public MyThread(String name){
this.name = name;
}
// 一定要重写Thread类中的run()方法,此方法为线程的主体
public void run(){
for(int i=0; i<10; i++){
System.out.println(name+"运行, i="+i);
}
}
}
实例化并运行下run()方法:
public class ThreadDemo01 {
public static void main(String[] args) {
MyThread mt1 = new MyThread("线程A");
MyThread mt2 = new MyThread("线程B");
mt1.run();
mt2.run();
}
}
线程A运行, i=0
线程A运行, i=1
线程A运行, i=2
线程A运行, i=3
线程A运行, i=4
线程A运行, i=5
线程A运行, i=6
线程A运行, i=7
线程A运行, i=8
线程A运行, i=9
线程B运行, i=0
线程B运行, i=1
线程B运行, i=2
线程B运行, i=3
线程B运行, i=4
线程B运行, i=5
线程B运行, i=6
线程B运行, i=7
线程B运行, i=8
线程B运行, i=9
要想使用多线程,必须调用从Thread类中继承来的start()方法。
public class ThreadDemo02 {
public static void main(String[] args) {
MyThread mt1 = new MyThread("线程A");
MyThread mt2 = new MyThread("线程B");
mt1.start();
mt2.start();
}
}
运行结果:(可能的一种)
线程B运行, i=0
线程A运行, i=0
线程B运行, i=1
线程A运行, i=1
线程B运行, i=2
线程A运行, i=2
线程B运行, i=3
线程A运行, i=3
线程B运行, i=4
线程A运行, i=4
线程B运行, i=5
线程B运行, i=6
线程A运行, i=5
线程B运行, i=7
线程A运行, i=6
线程A运行, i=7
线程A运行, i=8
线程A运行, i=9
线程B运行, i=8
线程B运行, i=9
注:如果一个类通过继承Thread类来实现,那么只能调用一次start()方法,若调用多次就会抛出异常
mt1.start();
mt2.start();
异常:java.lang.IllegalThreadStateException
3、Runnable接口
下面通过实例看实现Runnable接口如何启动多线程
还是那个线程类我们让他实现Runnable接口
public class MyThread2 implements Runnable{
private String name;
public MyThread2(String name){
this.name = name;
}
// 重写Runnable接口中的run()方法
public void run(){
for(int i=0; i<10; i++){
System.out.println(name+"运行, i="+i);
}
}
}
实例化启动线程:
public class ThreadDemo04 {
public static void main(String[] args) {
MyThread2 mt1 = new MyThread2("线程A");
MyThread2 mt2 = new MyThread2("线程B");
Thread t1 = new Thread(mt1);
Thread t2 = new Thread(mt2);
t1.start();
t2.start();
}
}
线程A运行, i=0
线程B运行, i=0
线程A运行, i=1
线程B运行, i=1
线程A运行, i=2
线程B运行, i=2
线程A运行, i=3
线程A运行, i=4
线程A运行, i=5
线程A运行, i=6
线程A运行, i=7
线程A运行, i=8
线程A运行, i=9
线程B运行, i=3
线程B运行, i=4
线程B运行, i=5
线程B运行, i=6
线程B运行, i=7
线程B运行, i=8
线程B运行, i=9
要想启动一个多线程,必须调用start()方法,如果继承thread类就可以直接使用其start()方法;Runnable接口没有start()方法的定义,还是要依靠thread类。
实例化Runnable子类对象--->用Runnable实例去实例化Thread类对象----->启动线程通过thread实例对象
4、Thread类与Runnable接口
Thread类:通过子类继承,有单继承局限;不能一个实例重复调用start()方法,不能实现资源共享。
Runnable:避免单继承局限;可被多个线程共享;
下面通过一个卖票的实例来对比资源共享的问题
定义一个线程类继承Thread类:
public class MyThread3 extends Thread{
private int ticket = 5;//一共5张票
public void run(){
for(int i=0; i<100; i++){//超出票数的循环,卖完即止
if(ticket > 0){
System.out.println("卖票:ticket="+ticket--);
}
}
}
}
实例化启动线程:
public class ThreadDemo05 {
public static void main(String[] args) {
MyThread3 my1 = new MyThread3();
MyThread3 my2 = new MyThread3();
MyThread3 my3 = new MyThread3();
my1.start();
my2.start();
my3.start();
}
}
卖票:ticket=5
卖票:ticket=5
卖票:ticket=5
卖票:ticket=4
卖票:ticket=3
卖票:ticket=4
卖票:ticket=2
卖票:ticket=1
卖票:ticket=3
卖票:ticket=4
卖票:ticket=2
卖票:ticket=1
卖票:ticket=3
卖票:ticket=2
卖票:ticket=1
以上启动了三个线程,但是每个线程却卖了各自的5张票,没有实现资源共享。
实现Runnable接口,来线程资源共享
定义一个线程类实现Runnable接口:
public class MyThread4 implements Runnable{
private int ticket = 5;
@Override
public void run() {
for(int i=0; i<100; i++){
if(ticket > 0){
System.out.println("卖票:ticket="+ticket--);//第一次循环ticket--为5,ticket变为4
}
}
}
}
实例化调用Thread的start()启动线程:
public class ThreadDemo06 {
public static void main(String[] args) {
MyThread4 my = new MyThread4();
new Thread(my).start();
new Thread(my).start();
new Thread(my).start();
}
}
卖票:ticket=5
卖票:ticket=3
卖票:ticket=4
卖票:ticket=1
卖票:ticket=2