程序在计算机运行为了提高效率便不能使用单一线程,所以多线程的出现解决了这个单线程效率低的问题,
在了解线程中,要先分清进程和线程。
1:一个程序有可以是有多个进程来运行的,每个进程有自己独立的内存空间去运行操作数据。
2:线程是处于进程中的更小执行单位,每个进程中有多个线程,每个线程有独立的内存空间去操作对象中的变量,又共同享有,同一块内存空间存放共同处理的对象。
由大到小的顺序是:程序>进程>线程
正常默认创建的线程是异步线程,线程还有一种是同步线程
异步线程:多个线程可以同时对一个对象进行操作。
同步线程:线程不能同时对一个对象进行操作。
有三种能创建线程的方式:(以下3种例子的线程都为异步线程)
方法1:将所需要的类去继承Thread类,Thread类是在java的lang包中。继承Thread,重写run的方法,在主类main中去创建线程对象,并调用Thread中的start 方法。 代码如下:
public class Demo{ public static void main(String [] args){ //创建一个ThreadTest 线程 t1 ThreadTest t1 = new ThreadTest(10,"线程A"); // t调用方法start() 通知cpu调用run方法执行 t1.start(); //创建一个ThreadTest 线程 t2 ThreadTest t2 = new ThreadTest(10,"线程B"); t2.start(); } //继承Thread 的ThreadTest类 static class ThreadTest extends Thread{ //定义一个变量num,线程名字name; int num; String name; //重写构造方法传入参数num,name public ThreadTest(int num,String name) { super(); this.num = num; this.name = name; } //重写run方法 public void run(){ //重写的方法run中调用Test方法 Test(); } public void Test(){ for(int i = 0;i<20;i++){ System.out.println(name+"<>"+num++); } } } }
方法2:实现接口runnable也可以创建线程,runnable中不能直接用Thread的方法,所以需要创建一个Thread对象来包装由实现runnable接口的线程创建的对象,再用包装好的Thread对象来调用Thread中的 start方法。 代码如下:
public class Demo1 { /** * @param args */ public static void main(String[] args) { //创建RunnableTest类的第一个线程t1 RunnableTest r1 = new RunnableTest(10,"线程A"); //用Thread包装r1对象 Thread t1 = new Thread(r1); t1.start(); //创建RunnableTest类的第二个线程t2 RunnableTest r2 = new RunnableTest(10,"线程B"); //用Thread包装r1对象 Thread t2 = new Thread(r2); t2.start(); } static class RunnableTest implements Runnable{ int num; String name; //重载构造函数 public RunnableTest(int num,String name){ this.name = name; this.num = num; } @Override //重写run方法 public void run() { //调用 Test()方法 Test(); } public void Test(){ for(int i = 0;i<20;i++){ System.out.println(name+"执行了 "+num++); } } } }
方法3:在java的util包中有timer和timertast类,实现timertast类,也可以创建线程,timertast是定时器类
代码如下:
import java.util.Timer; import java.util.TimerTask; public class Demo2 { /** * @param args */ public static void main(String[] args) { //创建一个Timertest对象 Timertest t = new Timertest(10,"线程A"); //用Timer创建定时器对象t1 Timer T = new Timer(); //用定时器对象调用方法, T.schedule(t, 100); //创建一个Timertest对象 Timertest t1 = new Timertest(10,"线程B"); //用Timer创建定时器对象T1 Timer T1 = new Timer(); //用定时器对象调用方法, T1.schedule(t1, 100); } static class Timertest extends TimerTask{ int num; String name; public Timertest(int num,String name){ this.name = name; this.num = num; } @Override //重写run方法 public void run() { Test(); } public void Test(){ for(int i = 0;i<20;i++){ System.out.println(name+"执行了 "+num++); } } } }
上面3种方法都可以创建线程,(例子中的一些方法未注释,自己查API文档,在什么包中都有注明)。
在异步线程中,继承Thread后中有许多方法时比较常用的。
例如:Thread.currentThread() 获得当前线程对象
Thread.sleep(毫秒) 当前线程休眠指定的毫秒数
setPriority(1~10); 设置线程的优先级 (1~10,数字越大,优先级越高,默认为5)
getPriority(); 获得线程的优先级
join() 等待该线程执行完毕(也称合并线程,单线程,指等一个线程执行结束后,再执行 另一个线程)
yield() 暂停当前正在执行的线程对象,并执行其他线程(当前线程让出执行的时间片段,由下一个线程使用。也有可能下个线程还是自己,所以不是绝对)。
getState() 获得线程的状态
isAlive() 是不是活动的线程(不常用)
start() 启动线程的方法(常用)(只是给虚拟机一个信号,当前这个线程可以执行run方法了 线程的run 方法什么时候开始执行,是由CPU调度的)
线程中存在五种状态:
新建状态:处于创建状态,未调用start()方法。
runnable:就绪状态,调用start()方法,等待CPU调度。
running :cpu调度后,处于运行状态。
not running:处于阻塞状态下,暂停状态(可能由于方法join()或者yield()而导致的状态)。
dead:线程执行结束时的死亡状态。
在同步线程中不可以对同一个对象进行操作,所以当一个线程在操作时,另一个线程必须等到前一个线程执行结束才可以接着执行,有4种方法可以实现线程的同步。
方法一:synchronized
方式一:使用synchronized(对象) 锁住需要同步的代码块
方法二:使用synchronized锁住需要同步的方法
方法三:从jdk1.5开始提供的对象锁
Lock l = new ReentrantLock();
//上锁
l.lock();
//解锁
l.unlock();
方法四:使用wait-notify机制
线程在现在的B/S主流情况下时非常实用的,一个网页是要同时支持多人浏览的,所以在多线程情况下,一(网页)对多(用户)的情况就可以解决。