Java多线程总结
程序员文章站
2022-03-22 15:19:34
...
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
进程(英语:process)是计算机中已运行程序的实体。进程为曾经是分时系统的基本运作单位。
一个进程可以有很多线程,每条线程并行执行不同的任务。
(来自慕课网的代码实例)
主类:
import java.io.*; public class Stage extends Thread { public static void main(String[] args) { new Stage().start(); } public void run(){ System.out.println("欢迎观看隋唐演义"); try { Thread.sleep(1000); } catch (InterruptedException e1) { e1.printStackTrace(); } System.out.println("大幕徐徐拉开"); try { Thread.sleep(1000); } catch (InterruptedException e1) { e1.printStackTrace(); } System.out.println("话说隋朝末年,隋军与农民起义军杀得昏天黑地..."); ArmyRunnable armyTaskOfSuiDynasty = new ArmyRunnable(); ArmyRunnable armyTaskOfRevolt = new ArmyRunnable(); /** * 创建两个线程 */ Thread armyOfSuiDynasty = new Thread(armyTaskOfSuiDynasty,"隋军"); Thread armyOfRevolt = new Thread(armyTaskOfRevolt,"农民起义军"); /** * 启动线程,让军队开始作战 */ armyOfSuiDynasty.start(); armyOfRevolt.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("正当双方激战正酣,半路杀出了个程咬金"); Thread mrCheng = new KeyPersonThread(); mrCheng.setName("程咬金"); System.out.println("程咬金的理想就是结束战争,使百姓安居乐业!"); /** * 停止前两个线程 */ armyTaskOfSuiDynasty.keepRunning = false; armyTaskOfRevolt.keepRunning = false; try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } mrCheng.start(); // 开始第三个线程 try { mrCheng.join(); // 新进程加入,join() 方法会在该线程结束之前一直占用CPU } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("战争结束,人民安居乐业,程先生实现了积极的人生梦想,为人民作出了贡献!"); System.out.println("谢谢观看隋唐演义,再见!"); } }
辅助类:
class ArmyRunnable implements Runnable { volatile boolean keepRunning = true; // volatile 单独说明 @Override public void run() { while(keepRunning){ for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName()+"进攻对方["+i+"]"); Thread.yield(); // yield() 方法单独说明 } } System.out.println(Thread.currentThread().getName()+"结束了战斗!"); } } class KeyPersonThread extends Thread { public void run(){ System.out.println(Thread.currentThread().getName()+"开始了战斗!"); for(int i=0;i<10;i++){ System.out.println(Thread.currentThread().getName()+"左突右杀,攻击隋军..."); } System.out.println(Thread.currentThread().getName()+"结束了战斗!"); } }
join() 方法的详细说明:
(01) 在“主线程main”中通过 new ThreadA("t1") 新建“线程t1”。 接着,通过 t1.start() 启动“线程 t1”,并执行t1.join()。
(02) 执行t1.join()之后,“主线程main”会进入“阻塞状态”等待t1运行结束。“子线程t1”结束之后,会唤醒“主线程main”,“主线程”重新获取cpu执行权,继续运行。
volatile 变量的说明:
1)(适用于Java所有版本)读和写一个volatile变量有全局的排序。也就是说每个线程访问一个volatile作用域时会在继续执行之前读取它的当前值,而不是(可能)使用一个缓存的值。(但是并不保证经常读写volatile作用域时读和写的相对顺序,也就是说通常这并不是有用的线程构建)。
2)(适用于Java5及其之后的版本)volatile的读和写建立了一个happens-before关系,类似于申请和释放一个互斥锁。
yield() 方法的说明:
会使当前线程由执行状态变为让步状态,但不代表下次执行的线程必然是其它的线程,该方法执行后当前线程会处于竞争状态,因此下次执行的线程依然可能是上次执行的线程(这里假设各个线程优先级相同)。