首页 > 编程 > Java > 正文

[JAVA] 多线程

2019-11-08 18:35:44
字体:
来源:转载
供稿:网友

参考视频: 深入浅出java多线程

一. 线程实现

类: Thread接口:Runnable重写方法public void run() { // 具体动作代码。。。。}

二. 常用Thread方法

1. static void sleep(), 睡眠

// 给予足够时间让军队停下来, 睡眠5s try { Thread.sleep(2000); } catch (InterruptedException e) { e.PRintStackTrace(); }

2. void join(), 其他线程等待这个线程运行结束,才能继续运行

// 万众瞩目, 所有线程等待程咬金完成历史使命try { mrCheng.join(); } catch (InterruptedException e) { e.printStackTrace(); }

3. static void yield(), 让出处理器时间

for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + "进攻对方[" + i + "]"); // 让出处理器时间, 下次该谁进攻改不一定呢 Thread.yield(); }

三. 名词解释

1. 原子性(Atomicity)

原子是世界上的最小单位,具有不可分割性。比如 a=0;(a非long和double类型) 这个操作是不可分割的,那么我们说这个操作时原子操作。再比如:a++; 这个操作实际是a = a + 1;是可分割的,所以他不是一个原子操作。非原子操作都会存在线程安全问题,需要我们使用同步技术(sychronized)来让它变成一个原子操作。一个操作是原子操作,那么我们称它具有原子性。Java的concurrent包下提供了一些原子类,我们可以通过阅读API来了解这些原子类的用法。比如:AtomicInteger、AtomicLong、AtomicReference等

2. 可见性(Visibility, 保证线程可以正确读取其他线程写入的值)

可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的。也就是一个线程修改的结果。另一个线程马上就能看到。比如:用volatile修饰的变量,就会具有可见性。volatile修饰的变量不允许线程内部缓存和重排序,即直接修改内存。所以对其他线程是可见的。但是这里需要注意一个问题,volatile只能让被他修饰内容具有可见性,但不能保证它具有原子性。比如 volatile int a = 0;之后有一个操作 a++;这个变量a具有可见性,但是a++ 依然是一个非原子操作,也就这这个操作同样存在线程安全问题。

3.有序性(Ordering)

Java内存模型中的程序天然有序性可以总结为一句话:如果在本线程内观察,所有操作都是有序的;如果在一个线程中观察另一个线程,所有操作都是无序的。前半句是指“线程内表现为串行语义”,后半句是指“指令重排序”现象和“工作内存主主内存同步延迟”现象。

Java语言提供了volatile和synchronized两个关键字来保证线程之间操作的有序性,volatile关键字本身就包含了禁止指令重排序的语义,而synchronized则是由“一个变量在同一时刻只允许一条线程对其进行lock操作”这条规则来获得的,这个规则决定了持有同一个锁的两个同步块只能串行地进入

四. 停止线程方法

正确停止方法, 利用可见性

1. 线程内增加volatile字段,run()方法里判断此字段
volatile boolean keepRunning = true; @Override public void run() { while(keepRunning) { ...... } }

说明: 效果是会等一个完整循环跑完后停止

错误停止方法
1. public final void stop()(final修饰,不能被重写)
Thread.stop();

说明:效果是程序没有跑完就戛然而止

2. public void interrupt()
mCheng.interrupt();

说明: - 效果是中断一下程序,程序继续运行。 - 调用interrput()方法,线程的状态变成被打断, 可调用下面两个方法判断程序是否被中断。 public static boolean interrupted() public boolean isInterrupted() - 调用完interrupt(), 在调用join(), join(long), join(long, int), sleep(long), or sleep(long, int)等方法后, 中断状态会被置位,调用interrupted()、isInterrupted()方法返回false.

五. 完整demo程序, 参考文首参考视频:隋唐演义

/** * 军队线程 * 模拟作战双方的行为 * Created by Danny on 2017/2/16. */public class ArmyRunnable implements Runnable { // 保证线程可以正确读取其他线程写入的值 // 可见性 volatile boolean keepRunning = true; @Override public void run() { while(keepRunning) { // 发动5连击 for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + "进攻对方[" + i + "]"); // 让出处理器时间, 下次该谁进攻改不一定呢 Thread.yield(); } } System.out.println(Thread.currentThread().getName() + "结束了战斗!"); }}/** * 关键人物线程 * 模拟关键人物作战行为 * Created by Danny on 2017/2/16. */public class KeyPersonThread extends Thread { @Override public void run() { super.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() + "结束了战斗!"); }}/** * 隋唐演义大舞台 * Created by Danny on 2017/2/16. */public class Stage extends Thread { @Override public void run() { super.run(); System.out.println("欢迎观看隋唐演义"); // 给时间让观众安静 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("大幕徐徐拉开"); // 拉开序幕 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("话说隋朝末年, 隋军与农民起义军杀得昏天暗地......"); ArmyRunnable armyTaskOfSuiDynasty = new ArmyRunnable(); ArmyRunnable armyTaskOfRevolt = new ArmyRunnable(); // 创建线程 Thread armyOfSuiDynasty = new Thread(armyTaskOfSuiDynasty, "隋军"); Thread armyOfRevolt = new Thread(armyTaskOfSuiDynasty, "农民起义军"); // 启动线程让军队开始作战 armyOfSuiDynasty.start(); armyOfRevolt.start(); // 舞台休眠,大家专心观看军队厮杀 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } // 停止作战// armyTaskOfSuiDynasty.keepRunning = false;// armyTaskOfRevolt.keepRunning = false;////// try {// armyOfRevolt.join();// } 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(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("战争结束, 人民安居乐业, 程咬金实现了积极的人生梦想, 为人民作出了贡献"); System.out.println("谢谢观看隋唐演义, 再见!"); }}public static void main(String[] args) { // 隋唐演义入口 new Stage().start();}
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表