[JAVA] 多线程
来源:互联网 发布:android 美团外卖源码 编辑:程序博客网 时间:2024/05/22 15:06
参考视频: 深入浅出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();}
- 【Java多线程】多线程死锁
- Java 多线程
- java 多线程
- java多线程
- JAVA多线程
- java多线程
- JAVA多线程
- java多线程
- JAVA 多线程
- Java多线程
- java多线程
- JAVA 多线程
- Java 多线程
- Java 多线程
- java多线程
- Java 多线程
- Java多线程
- java 多线程
- POJ 1753 Flip Game (枚举)
- 【学习总结】线程间锁机制
- 查询A库数据插入至B库中
- 浅谈linux系统下的进程通信之管道pipe
- 为什么php开发网站比javaweb简单很多很多,javaweb却还占有很大市场? - 请在web发展历史中找答案
- [JAVA] 多线程
- intersectLineMesh3d
- idea破解
- Linux下安装Lnmp环境之Mysql(二)
- mysql插入中文乱码问题
- 表单取消监听数据变化
- 优秀设计师不得不知道的用户体验设计(一)
- npm init node 通过指令创建一个package.json文件及npm安装package.json
- 按键监听