JAVA多线程 总结
来源:互联网 发布:vmware player linux 编辑:程序博客网 时间:2024/05/17 23:25
未完待续Loading...
通过继承自Thread:
class Player extends Thread{String name;Player(String name){this.name=name;}@Overridepublic void run(){for(int i=0;i<3;i++)System.out.println(name+"正在奔跑中"+i);}}public class ThreadTest {public static void main(String []args){Player aPlayer=new Player("刘翔");Player bPlayer=new Player("博尔特");aPlayer.start();bPlayer.start();}}
运行结果:
刘翔正在奔跑中0博尔特正在奔跑中0博尔特正在奔跑中1博尔特正在奔跑中2刘翔正在奔跑中1刘翔正在奔跑中2
实现Runnable接口
class Car implements Runnable{String name;Car(String name){this.name=name;}@Overridepublic void run() {for(int i=0;i<3;i++)System.out.println(name+"正在运行中"+i);}}public class ThreadTest {public static void main(String []args){Car aCar=new Car("法拉利");Car bCar=new Car("奔驰");Thread t1=new Thread(aCar);Thread t2=new Thread(bCar);t1.start();t2.start();}}
奔驰正在运行中0法拉利正在运行中0法拉利正在运行中1法拉利正在运行中2奔驰正在运行中1奔驰正在运行中2
继承自Thread与实现Runnable接口的区别
class Shop extends Thread{String name;Shop(String name){this.name=name;}private int count=3;@Overridepublic void run(){for(int i=0;i<3;i++)if(count>=0)System.out.println(name+"卖出一张票,还剩"+--count);}}public class ThreadTest {public static void main(String []args){Shop aShop=new Shop("窗口1 ");Shop bShop=new Shop("窗口2 ");aShop.start();bShop.start();}}
运行结果:
窗口1 卖出一张票,还剩2窗口2 卖出一张票,还剩2窗口1 卖出一张票,还剩1窗口2 卖出一张票,还剩1窗口1 卖出一张票,还剩0窗口2 卖出一张票,还剩0
class Shop implements Runnable{private int count=5;@Overridepublic void run(){for(int i=0;i<20;i++)if(this.count>=0)System.out.println(Thread.currentThread().getName()+"卖出一张票,剩"+count--);}}public class ThreadTest {public static void main(String []args){Shop shop=new Shop();new Thread(shop,"窗口一").start();new Thread(shop,"窗口二").start();}}
运行结果:
窗口一卖出一张票,剩5窗口二卖出一张票,剩4窗口一卖出一张票,剩3窗口二卖出一张票,剩2窗口一卖出一张票,剩1窗口二卖出一张票,剩0
main方法其实也是一个线程。在java中所以的线程都是同时启动的,至于什么时候,哪个先执行,
在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使
动了一个进程。
线程的强制执行:
public class ThreadTest implements Runnable {@Overridepublic void run(){for(int i=0;i<3;i++)System.out.println(Thread.currentThread().getName());}public static void main(String []args){ThreadTest threadTest=new ThreadTest();Thread thread=new Thread(threadTest,"线程");System.out.println("线程是否执行中"+thread.isAlive());thread.start();System.out.println("线程是否执行中"+thread.isAlive());for(int i=1;i<=5;i++){if(i>3){try{thread.join();}catch(Exception e){e.printStackTrace();}}System.out.println("主线程执行中"+i);}}}
运行结果:
线程是否执行中false线程是否执行中true主线程执行中1主线程执行中2主线程执行中3线程线程线程主线程执行中4主线程执行中5
线程的休眠:
public class ThreadTest implements Runnable {@Overridepublic void run(){for(int i=0;i<3;i++){System.out.println("线程执行中"+i);try{Thread.sleep(1000);}catch(Exception e){e.printStackTrace();}}}public static void main(String []args){ThreadTest threadTest=new ThreadTest();new Thread(threadTest).start();}}
运行结果:
线程执行中0线程执行中1线程执行中2
线程中断:
当线程的 run 方法执行完,并由 return 语句返回时,或是在方法中出现了未捕获的异常,
当对线程调用 interrupt 方法时, 线程的中断状态将会置位。每个线程都具有boolean标志,
如:
while(!Thread.currentThread().isInterrupted()&& more word to do){do mo work;}
但是如果线程阻塞,将无法检测中断状态,这里将会产生 InterruptedException 当一个阻塞
没有任何语言方面的需求要求一个被中断的线程应该终止,中断线程只是引起它的注意,被中断
简单的将线程中断作为一个终止请求。该类 run 方法如:
public void run(){try{...while(!Thread.currentThread().isInterrupted()&& more work to do){do more work;}}catch(InterruptedException e){//Thread was interrupted during sleep or wait}finally{cleanup,if required;}//exiting the run method teminates the thread}
如果线程在中断状态被置位时调用 sleep 方法,并不会休眠,而是清除中断状态并且
public class ThreadTest implements Runnable {@Overridepublic void run(){System.out.println("执行run方法");try {Thread.sleep(10000);System.out.print("线程完成休眠");} catch (InterruptedException e) {System.out.println("线程休眠被打断");return ;}finally{System.out.println("线程状态"+Thread.currentThread().isInterrupted());}System.out.println("线程正常终止");}public static void main(String []args){ThreadTest threadTest=new ThreadTest();Thread thread=new Thread(threadTest);thread.start();try {Thread.sleep(2000);} catch (Exception e) {e.printStackTrace();}thread.interrupt();}}
运行结果:
执行run方法线程休眠被打断线程状态false
void interrupt()/*向线程发送中断请求。线程的中断状态设置为true。如果当前线程被sleep调用阻塞,将会抛出 InterruptedException*/static boolean interrupted()//测试当前线程是否为被中断,会产生副作用将当前线程中断状态设置为 falseboolean isInterrupted() //测试线程是否被终止,不会改变中断状态static Thread currentThread() //返回当前执行线程的Thread对象
public class ThreadTest implements Runnable {@Overridepublic void run(){for(;;)System.out.println("线程执行中");}public static void main(String []args){ThreadTest threadTest=new ThreadTest();Thread thread=new Thread(threadTest);thread.setDaemon(true);thread.start();}}
虽然设置成为了死循环,但是程序还是可以运行完成的,因为死循环中的线程操作已经设
线程同步:
public class ThreadTest implements Runnable {private int ticket=5;private int money=0;@Overridepublic void run(){String name=Thread.currentThread().getName();while(ticket>=1){sell();}}//sell 部分 进行售票收费操作public void sell(){String name=Thread.currentThread().getName();if(ticket>=1){System.out.println(name+"开始卖票了");ticket--;//执行一个无意义的耗时操作,让售票与收费可能不能一次性完成for(int j=1;j<=1000;j++)Math.sin(j);money++;System.out.println("ticket = "+ticket+"\t money= "+money);}}public static void main(String []args){ThreadTest threadTest=new ThreadTest();new Thread(threadTest,"窗口一").start();;new Thread(threadTest,"窗口二").start();}}
运行结果:
窗口一开始卖票了窗口二开始卖票了ticket = 3money= 2ticket = 3money= 2窗口二开始卖票了窗口一开始卖票了ticket = 1money= 3ticket = 1money= 4窗口二开始卖票了窗口一开始卖票了ticket = -1money= 5ticket = -1money= 6
结果中出现了负数,这是因为线程不同步导致的后果,比如,当 ticket=1的时候,窗口一
线程判断条件 ticket>=1 进入 执行sell部分,首先打印出"窗口一开始售票",然后该部分没有完全结束,这时ticket并没有执行 ticket-- 部分,所以仍然为 1,此时可能又轮到窗口二线程执
行,判断条件ticket>=1 于是又进入了 sell 部分,这时候就可以理解了,在ticket=1的时候,
两个线程都 已经 进入了sell的部分,自然会发生ticket=-1的情况了。
为了能够进行同步,可以通过以下几种方法修改上面的代码:
可以使用 使用 synchronized 关键字将 sell 方法设置为 同步方法:
synchronized public void sell(){//more code ...}
为类添加一个锁作为成员变量,并将 sell 方法修改,给出部分代码:
// more code ...private Lock lock=new ReentrantLock();public void sell(){lock.lock();try {if(ticket>=1){///more code ...}} finally{lock.unlock();}}//more code ...
设置同步之后,运行结果:
窗口一开始卖票了
ticket = 4money= 1
窗口一开始卖票了
ticket = 3money= 2
窗口二开始卖票了
ticket = 2money= 3
窗口二开始卖票了
ticket = 1money= 4
窗口一开始卖票了
ticket = 0money= 5
下面是个银行转账的例子:
程序主要功能是,已有100个账户,并且每个账户都预先有1000元的余额,然后为每个账户
开启了一个线程,用于将余额转账到一个随机的账户。
class Bank{private double accounts[];Bank(int n,double initMoney){accounts=new double[n];for(int i=0;i<n;i++)accounts[i]=initMoney;} //从 from 账户 转 amount 元 到账户 to public void transfer(int from,int to ,double amount){ if(accounts[from]<amount)return ; System.out.print(Thread.currentThread().getName()); accounts[from]-=amount; System.out.printf("%10.2f from %d to %d ", amount,from,to); accounts[to]+=amount; System.out.printf("Total money =%10.2f\n",getTotalMoney());} //计算所有账户余额总和public double getTotalMoney(){double sum=0;for(double a:accounts)sum+=a;return sum;}//获取账户总数量public int getSize(){return accounts.length;}//获取指定账户余额public double getMoney(int from){return accounts[from];}}
public class ThreadTest implements Runnable{private Bank bank;private int fromAccount;//当前要转账的账户private double maxAmount;//转账最大额private int DELAY=10;public ThreadTest(Bank bank,int from,double max){this.bank=bank;fromAccount=from;maxAmount=max;}@Overridepublic void run(){try {while(true){int toAccount=(int)(bank.getSize()*Math.random());double amount=(long)(maxAmount*Math.random());bank.transfer(fromAccount, toAccount, amount);Thread.sleep((long)(DELAY*Math.random()));}} catch (InterruptedException e) {}}public static void main(String []args){Bank bank=new Bank(100, 1000);for(int i=0;i<100;i++)new Thread(new ThreadTest(bank, i, 1000)).start();}}
在没有进行同步的情况下,可以看到刚开始的时候,总额度没有什么问题,然而运行到了后期的
时候,突然发现账户总额出现了问题,原因上面已经说明,因为转出账户余额减少与转入账户余额增加
不是原子操作。
Thread-20 40.00 from 20 to 47 Total money = 100000.00
Thread-33 647.00 from 33 to 54 Total money = 100000.00
Thread-72 579.00 from 72 to 69 Total money = 100000.00
...
Thread-31 299.00 from 31 to 8 Total money = 99463.00
Thread-98 854.00 from 98 to 6 Total money = 99463.00
那可以通过增加锁的方式设置临界区,并修改 transfer方法:
//more code ...private Lock lock=new ReentrantLock();public void transfer(int from,int to ,double amount){ lock.lock(); try { if(accounts[from]<amount)return ; //more code... } finally { lock.unlock(); } }//more code ...
但是有时线程在进入临界区之后,发现还需要满足条件才能执行。就需要设置一个条件来管理
那些已经获得了锁却不能进行有效工作的进程.
但是如果只是单纯的进行这样的操作:
if(bank.getMoney(fromAccount)>=amount)transfer(fromAccount,toAccount,amount);
有可能在执行条件判断后,执行 transfer 方法前 线程就已经中断了
而如果将 transfer 方法修改为这样,如果当获得了锁的进程中的余额不足时,将会一直等待其他
账户将余额转入,而因为已经获得了此锁,所以其它账户没有进行余额操作的机会.
public void transfer(int from,int to ,double amount){ lock.lock(); try { while(accounts[from]<amount); //more code... } finally { lock.unlock(); } }
于是可以使用条件对象,
//more code ...private Condition condition;public Bank(int n,double initMoney){condition=lock.newCondition();//more code ..}//more code ...public void transfer(int from,int to ,double amount){ lock.lock(); try { while(accounts[from]<=amount) condition.await(); //more code ... condition.signalAll(); } catch (InterruptedException e) {e.printStackTrace();} finally { lock.unlock(); }}//more code ...
如果当前账户余额不足,线程阻塞,并且会放弃锁,然后其它线程就有机会继续获得此锁。等待获得锁
的线程与调用 awit 方法的线程有本质的区别。一旦一个线程调用 awit 方法,将会进入当前条件的等待集
当锁可用时,该线程不能马上解除阻塞,它会继续处于阻塞状态,直到其他线程调用 signalAll 方法。这一
方法仅仅只是通知因为该条件而进入等待集的所有进程,将这些进程从等待集中移除,他们将被激活,一旦锁
继续可用,将回试图重新进入对象,从 awit 犯法调用处返回,获得该锁并从被阻塞的地方继续执行.
Condition newCondition()//返回一个与该锁相关的条件对象void awit()//将该线程放到条件的等待集中void signalAll()//解除该条件等待集中所有线程的阻塞状态void signal()//解除该条件等待集中某一个线程的阻塞状态
- 【多线程】java多线程知识点总结
- java多线程使用总结
- Java多线程编程总结
- Java多线程编程总结
- Java多线程编程总结
- java多线程学习总结
- Java多线程编程总结
- Java多线程编程总结
- java多线程学习总结
- Java多线程编程总结
- Java多线程编程总结
- Java多线程编程总结
- Java多线程编程总结
- Java多线程编程总结
- Java多线程编程总结
- Java 多线程总结
- Java多线程编程总结
- Java多线程编程总结
- 想让安卓 APP 如丝般顺滑?
- ImageMagick 一个图像处理较好的库
- Swift 2.0 异常处理
- aspx+mssql后台登陆注入拿webshell
- 学习Android推送功能笔记(1)
- JAVA多线程 总结
- 浏览器兼容性解决方法
- 黑马程序员——java学习日记四
- iOS的管理机制
- 了解Android中的接口回调机制
- 基于servlet的方式实现文件上传
- iOS学习之sqlite的创建数据库,表,插入查看数据
- python多线程
- goaccess-nginx日志分析工具简介