多线程(一)
说起多线程不得不弄清几个“词”的含义:
进程:顾名思义就是正在执行中的程序,为了完成某个特定的任务、功能,而用某种编程语言编写的一组指令的集合。
线程:在操作系统中,进程是资源分配、调度和管理的最小单位。每个进程在内存中是独立的。
进程与线程之间的关系:线程是进程中的一条执行路径。
那么怎么开启线程哪?
a:继承 thread 类
b:实现 runnable接口
a方式的代码如下:
// 方式一:继承Thread类 class MyThreadMethod1 extends Thread { private static int ticket = 10; // 重写run方法: public void run() { while (true) { if (ticket > 0) {// 提升效率 synchronized (MyThreadMethod1.class) {// 保证线程安全。 if (ticket > 0) { System.out.println(getName() + "票数:" + ticket); ticket--; } } } else { break; } } } }
//测试方式一: @Test public void test() { // 定义3个线程 MyThreadMethod1 t1 = new MyThreadMethod1(); MyThreadMethod1 t2 = new MyThreadMethod1(); MyThreadMethod1 t3 = new MyThreadMethod1(); t1.start(); t2.start(); t3.start(); }
b:方式的代码如下:
// 方式二:实现Runnable接口,重写run方法 class MyThreadMethod2 implements Runnable { private static int ticket = 10; @Override public void run() { while (true) { if (ticket > 0) { synchronized (MyThreadMethod2.class) { if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "票数:" + ticket); ticket--; } } } } } }
//测试方式二: /** * 代理者模式的思想: * 测试:由于实现runnable接口后,并没有start方法,所以不能使用对象调用start() * 可以使用代理者模式,因为Thread和本类都实现了相同的接口runnable接口, * 使两者遵守同样的规范。 * 代理者持有被代理者的引用。 * 核心代码仍然需要被代理者本身去做,其他的一些问题可以交给代理者来做。 * * 本次的代理者与被代理者: * 代理者:Thread 要持有被代理者的引用 * 被代理者:MyThreadMethod2 * */ @Test public void test2() { // 定义3个线程:并且代理者持有被代理者的引用 Thread t1 = new Thread(new MyThreadMethod2()); Thread t2 = new Thread(new MyThreadMethod2()); Thread t3 = new Thread(new MyThreadMethod2()); //开启线程 t1.start(); t2.start(); t3.start(); }
继承Thread和实现Runnable接口的区别:
继承Thread的优点:
代码简洁。
实现Runnable接口的优势:
1.避免了单继承的局限性。
2.多个线程可以共享同一个接口子类的对象target,非常适合多个相同线程来处理同一份资源。
线程的生命周期:
新建:当一个Thread类的对象或子类对象被创建,此时的线程的状态称为"新建"。
就绪:当Thread类的对象或子类对象调用start()的时候,将进入线程队列等待CPU时间片,此时它已具备了运行的条件,此时线程的状态称为"就绪"状态。
运行:当就绪的线程被CPU调用,并获得资源时,此时进入"运行"的状态,执行的内容是定义的run()里面的定义的内容。
阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出 CPU 并临时中止自己的执行,进入阻塞状态。
消亡:线程完成了它的全部工作,或则被提前强制停止。
注意:由于stop的方法已经过时,建议谨慎使用,停止线程,可以定义一个标志状的标记符,根据标识符的状态来改变进程的状态。