-----------android培训、java培训、java学习型技术博客、期待与您交流!------------
1、对线程的理解
进程:每个独立执行的程序成为进程。
线程:线程就是进程内部的一条执行路径。
多线程:在一个进程中同时有多条执行路径。
线程和进程的区别如下:
(1) 每个进程都有独立的代码和数据空间(进程上下文),进程间的切换开销大。
(2) 同一进程内的多个线程共享相同的代码和数据空间,每个线程有独立运行栈 和线序计数器,线程间的切换开销小。
2、线程的创建和启动
实现线程的创建有两种方法:
(1) 实现Runnable接口
(2) 继承Thread类
启动方法:调用Thread实例的方法start()
示例:FirstThreadTest.java
/** 创建和启动多个线程 */ public class FirstThreadTest { public static void main(String[] args) { System.out.println("主线程开始执行"); Thread thread1 = new Thread(new MyRunner()); //启动第一个线程 thread1.start(); System.out.println("启动一个新线程(thread1)..."); Thread thread2 = new MyTread(); //启动第二个线程 thread2.start(); System.out.println("启动一个新线程(thread2)..."); System.out.println("主线程执行完毕"); } }
/** 实现自java.lang.Runnable来创建一个打算用线程来执行的类 */ public class MyRunner implements Runnable { public void run() { // 要在线程中执行的代码 for (int i = 0; i < 100; i++) { System.out.println("MyRunner:" + i); } } }
执行结果:
主线程开始执行 启动一个新线程(thread1)... MyRunner:0 MyRunner:1 MyRunner:2 MyRunner:3 启动一个新线程(thread2)... 主线程执行完毕 MyRunner:4 MyRunner:5 MyRunner:6 MyRunner:7 MyThread:0 MyRunner:8 ...... MyThread:94 MyThread:95 MyThread:96 MyThread:97 MyThread:98 MyThread:99
主线程中创建了两个子线程,这两个子线程会交替的执行,这就是多线程的程序。
3、线程的生命周期:
当创建Thread类的一个实例(对象)时,此线程进入新建状态(未被启动)。
例如:Thread t1=new Thread();
就绪(runnable)
线程已经被启动,正在等待被分配给CPU时间片,也就是说此时线程正在就绪队列中排队等候得到CPU资源。例如:t1.start();
运行(running)
线程获得CPU资源正在执行任务(run()方法),此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运行到结束。
死亡(dead)
当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。
自然终止:正常运行run()方法后终止
异常终止:调用stop()方法让一个线程终止运行
堵塞(blocked)
由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。
正在睡眠:用sleep(long t) 方法可使线程进入睡眠方式。一个睡眠着的线程在指定的时间过去可进入就绪状态。
正在等待:调用wait()方法。(调用motify()方法回到就绪状态)
被另一个线程所阻塞:调用suspend()方法。(调用resume()方法恢复)
线程睡眠示例:ThreadSleepTest
/** 线程睡眠示例 */ public class ThreadSleepTest { public static void main(String[] args) { System.out.println("主线程开始执行"); Thread thread1 = new Thread(new SleepRunner()); thread1.start(); System.out.println("启动一个新线程(thread1)..."); Thread thread2 = new Thread(new NormalRunner()); thread2.start(); System.out.println("启动一个新线程(thread2)..."); System.out.println("主线程执行完毕"); } } class SleepRunner implements Runnable{ public void run() { try { Thread.sleep(100); //线程睡眠100毫秒 } catch (InterruptedException e) { e.printStackTrace(); } // 要在线程中执行的代码 for (int i = 0; i < 100; i++) { System.out.println("SleepRunner:" + i); } } } class NormalRunner implements Runnable{ public void run() { // 要在线程中执行的代码 for (int i = 0; i < 100; i++) { System.out.println("NormalRunner:" + i); } } }
执行结果:
......... NormalRunner:96 NormalRunner:97 NormalRunner:98 NormalRunner:99 SleepRunner:0 SleepRunner:1 SleepRunner:2 SleepRunner:3 SleepRunner:4 SleepRunner:5 .......
轮到SleepRunner时,使它休眠,先执行NormalRunner,等SleepRunner休眠结束时,NormaRunner已经执行完毕。
线程让步示例:ThreadYieldTest
/** 线程让步示例 */ public class ThreadYieldTest { public static void main(String[] args) { //获取当前线程的名称 System.out.println(Thread.currentThread().getName()); Thread thread1 = new Thread(new YieldThread()); thread1.start(); Thread thread2 = new Thread(new YieldThread()); thread2.start(); } } class YieldThread implements Runnable{ public void run() { for(int i = 0; i < 100; i++){ System.out.println(Thread.currentThread().getName()+ ":" + i); if(i % 10 == 0){ //当i可以被10整除时,当前线程让步给其它线程 Thread.yield(); //线程让步的方法 } } } }
执行结果:
Thread-1:96 Thread-1:97 Thread-1:98 Thread-1:99 Thread-0:76 Thread-0:77 Thread-0:78 Thread-0:79
每到条件达成时都会做出线程让步的动作
线程的加入示例:ThreadJoinTest
/** 线程合并操作 */ public class ThreadJoinTest { public static void main(String[] args) { Thread thread1 = new Thread(new MyThread3()); thread1.start(); //主线程中执行for循环 for (int i = 1; i <= 50; i++) { System.out.println(Thread.currentThread().getName() + ":" + i); if (i == 30) { try { thread1.join(); //把子线程加入到主线程中执行 } catch (InterruptedException e) { e.printStackTrace(); } } } } } class MyThread3 implements Runnable{ public void run() { for (int i = 1; i <= 20; i++) { System.out.println(Thread.currentThread().getName() + ":" + i); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }
执行结果
main:28 main:29 main:30 Thread-0:2 Thread-0:3 Thread-0:4 Thread-0:5 Thread-0:6
当主线程到达30时执行让步操作,子线程执行完成之后继续执行主线程
5、多线程中常用到的方法
1.sleep()方法
在指定时间内让当前正在执行的线程暂停执行,但不会释放"锁标志"。
sleep()使当前线程进入阻塞状态,在指定时间内不会执行。
2.wait()方法
在其他线程调用对象的notify或notifyAll方法前,导致当前线程等待。线程会释放掉它所占有的"锁标志",从而使别的线程有机会抢占该锁。
当前线程必须拥有当前对象锁。
waite()和notify()必须在synchronized函数或synchronized block中进行调用。
3.yield方法
暂停当前正在执行的线程对象。
yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。
yield()只能使同优先级或更高优先级的线程有执行的机会。
4.join方法
等待该线程终止。
等待调用join方法的线程结束,再继续执行。如:t.join();//主要用于等待t线程运行结束,若无此句,main则会执行完毕,导致结果不可预测。
6、总结:
多线程并不是同时执行多条路径,而是系统分配执行时间,在同一时间还是只能进行一个执行路径,只是因为CPU的速度非常快,所以感觉是同时执行,就类似于十字路口的红绿灯,把同一个方向行驶的车辆分为直行走、左转、右转,红绿灯就是我们的系统,车辆就是就是我们执行的代码。