Java线程(一)
来源:互联网 发布:php开发流程 编辑:程序博客网 时间:2024/06/05 07:11
新建线程
继承Thread
实现Runnable
停止线程
stop方法是一个被废弃的方法,因为其是暴力的,即不管线程执行的状态如何,都会立刻停止线程,可能会引起数据不一致的情况,数据不一致的情况见如下代码:
public class UnformmatedStop { static class Person{ private String username; private String password; public String getUsename() { return username; } public void setUsename(String usename) { this.username = usename; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public synchronized void change(String username,String password){ this.username = username; try { //TODO other things Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } this.password = password; } public synchronized String read(){ return username + ","+password; } } static class Task implements Runnable{ private volatile Person p; public Task(Person p) { super(); this.p = p; } @Override public void run() { System.out.println(p.read()); } } static class Task2 implements Runnable{ private volatile Person p; public Task2(Person p) { super(); this.p = p; } @Override public void run() { p.change("lq", "084012151"); } } public static void main(String[] args) throws InterruptedException { Person p = new Person(); Thread tChange = new Thread(new Task2(p)); tChange.start(); Thread.sleep(3000); tChange.stop(); Thread tRead = new Thread(new Task(p)); tRead.start(); }}
结果如下:
lq,null
结果分析:tChange线程在写入username和password的时候,被强迫停止了,造成password没有被写成功,tRead读取的时候就会造成password为null了,这就造成了丢失更新的出现
正确的停止一个线程的方法
public class Stop { static class Task implements Runnable{ public volatile boolean stooped = false; @Override public void run() { while(!stooped){ System.out.println(Thread.currentThread().getName()+"正在运行"); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws InterruptedException { Task task = new Task(); Thread t1 = new Thread(task); t1.start(); Thread.sleep(3000); System.out.println("下面开始暂停线程t1的执行"); task.stooped = true; }}
注意:volatile的使用,volatile会保证可见性,但是不保证原子性(load,use,rewrite)这个整个过程的原子性
线程中断
线程中断并不会使线程立即退出,而是给线程发送一个通知,告知目标线程, 有人希望你退出啦!至于目标线程接到通知后如何处理,则完全由目标线程自行决定。这点很 重要,如果中断后,线程立即无条件退出,我们就又会遇到stop()方法的老问题。
/** * 线程中断并不会使线程立即退出,而是给线程发送一个通知,告知目标线程有人希望你退出了 * 至于目标线程接到通知后何时如何处理则由目标线程自行决定 */public class Interrupt implements Runnable{ @Override public void run() { while(true){ //中断的两个方法,interupt和isInterrupted(判断当前线程是否被中断)两个方法 /*if(Thread.currentThread().isInterrupted()){ System.out.println(Thread.currentThread().getName()+"已经被中断"); break; }*/ Thread.yield(); } } public static void main(String[] args) { Thread thread = new Thread(new Interrupt()); thread.start(); //在这里因为Runnable实现类中并没有对中断处理的逻辑,因此即使thread线程被设置了中断状态 //但是这个中断并不会发生任何作用,所以需要放开上面的注释部分,对线程的中断逻辑进行处理 thread.interrupt(); }}
当sleep遇上interrupt
public static native void sleep(long millis) throws InterruptedException
sleep方法会抛出InterruptedException异常
InterruptedException不是运行时异常,也就是说程序必须捕获并且处理它,当线程在sleep() 休眠时,如果被中断,这个异常就会产生
public class Sleep { static class Task implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"正在运行"); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"结束运行"); } } public static void main(String[] args) { Task task = new Task(); Thread t1 = new Thread(task); t1.start(); //阻断正在睡眠的线程,会使线程抛出中断异常,然后线程会退出休眠的状态,执行线程后面的代码 t1.interrupt(); }}
Thread-0正在运行java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at sync.Sleep$Task.run(Sleep.java:11) at java.lang.Thread.run(Unknown Source)Thread-0结束运行
线程的等待(wait)和通知(notify)
这里还需要强调一点,Objectwait()方法并不是可以随便调用的。它必须包含在对应的 synchronzied语句中,无论是wait()或者notify()都需要首先获得目标对象的一个监视器。
/** * 假设线程A调用了obj.wait方法,那么线程A就会被停止执行,转为等待状态(并且会释放锁),等待到何时结束呢?线程A会一直 * 等待到其他线程调用了obj.notify方法为止(调用obj.notify并不会释放锁),但是线程A在被唤醒后要做的第一件事并不是执行后续的代码,而是要 * 重新获取obj这个监视器,如果暂时获取不到就会等待这个监视器,当监视器到来后才会真正意义上的唤醒 * * 就像这里的线程2并不会在线程1,notify后就立刻执行后面的代码一样,这样就会存在延时 */public class WaitNotify { public static void main(String[] args) { final ListAdd listAdd = new ListAdd(); final Object lock = new Object(); Thread thread1 = new Thread(new Runnable() { @Override public void run() { synchronized (lock) { for(int i = 0;i<10;i++){ listAdd.add(); System.out.println(Thread.currentThread().getName()+"添加了一个元素"); if(listAdd.size()==5){ //notify必须与sychronized一起使用,notify表示不释放锁,wait表示释放锁 lock.notify(); } try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }); Thread thread2 = new Thread(new Runnable() { @Override public void run() { synchronized (lock) { if(listAdd.size()!=5){ try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+"遇到了size为5的情况"); throw new RuntimeException("size为5"); } } }); /** * 必须先启动线程2,因为只有这样,会先进入线程2的wait方法进行等待,并且释放锁,然后执行线程1 * 如果先启动线程1的话,线程1在size等于5的时候,并不会释放锁,而是继续往list里面添加数据直到全部完成释放锁, * 然后线程2执行的时候size已经是10了,不存在为5的情况了,实验结果就不对了 */ thread2.start(); thread1.start(); }}class ListAdd{ private volatile List list = new ArrayList(); public void add(){ list.add("jyw"); } public int size(){ return list.size(); }}
运行结果Thread-0添加了一个元素Thread-0添加了一个元素Thread-0添加了一个元素Thread-0添加了一个元素Thread-0添加了一个元素Thread-0添加了一个元素Thread-0添加了一个元素Thread-0添加了一个元素Thread-0添加了一个元素Thread-0添加了一个元素Thread-1遇到了size为5的情况Exception in thread "Thread-1" java.lang.RuntimeException: size为5 at sync.WaitNotify$2.run(WaitNotify.java:56) at java.lang.Thread.run(Unknown Source)
结果分析:刚开始的时候,listAdd的size不是5,所以就会wait,使得当前线程被挂起,等待notify,然后当i=5的时候,thread1会notify,但是此时thread1并没有释放lock对象监视器,所以thread2并不会立刻执行打印抛出异常,一定需要重新获得锁
- java线程(一)
- java线程(一)
- java 线程(一)
- JAVA线程(一)
- java线程(一)
- JAVA线程(一)
- Java 线程(一)
- Java线程(一)
- Java线程(一)
- JAVA线程(一)
- Java线程(一)
- java线程编程(一):线程基础
- Java线程和线程池(一)
- 驯服Java线程(一)
- Java的线程(一)
- java 线程学习(一)
- java线程安全(一)
- [Java] 线程中断(一)
- Codevs 3304 水果姐逛水果街Ⅰ
- 高级程序员的自我修养
- C# ORM 泛型与反射的交叉应用
- 23种设计模式(4):建造者模式
- 算法竞赛入门经典--训练指南 笔记
- Java线程(一)
- vue-cli手脚架模板使用sass
- Hibernate hql 2
- NOIP2016提高组Day1 真题测试
- linux环境导入导出postgres数据库表结构和表数据
- SAX和STAX解析xml文档
- CBoard框架使用总结一
- 一个C++新手碰到的
- 学生信息管理系统总结