线程
来源:互联网 发布:恩典壁纸软件 编辑:程序博客网 时间:2024/06/03 20:38
一、进程
1、运行时(Runtime)应用程序
2、进程之间的内存不是共享的(独占)
3、进程间通信使用的是socket(套接字)
=======================
二、多线程
1、进程内并发执行的代码段,关键就是并发
2、线程之间共享内存
3、创建灵活响应的桌面程序(QQ、迅雷)
4、每个运行着的线程对应一个栈stack
5、应用程序至少有一个线程(主线程)
====================
Java中使用线程继承java.lang.Thread
测试代码1:
public class ThreadDemo1{ public static void main(String[] arg){ MyThread t1 = new MyThread(); YourThread t2 = new YourThread(); t1.start(); t2.start(); }}class MyThread extends Thread{ public void run(){ for(;;){ System.out.println("hello world -1"); } }}class YourThread extends Thread{ public void run(){ for(;;){ System.out.println("hello world -2"); } }}
结果:
出现的顺序是随机的,但是一旦某个线程抢到资源后将抢占着,比较懒
测试代码2:
Thread.yield()方法:让当前线程让出cpu抢占权,具有谦让之意,瞬时的动作。
public class ThreadDemo2{ public static void main(String[] arg){ MyThread t1 = new MyThread("hello world-1"); MyThread t2 = new MyThread("hello world-2"); t1.start(); t2.start(); }}class MyThread extends Thread{ private String name; public MyThread(String name){ this.name = name; } public void run(){ for(;;){ System.out.println(name); //yield,放弃,谦让 Thread.yield(); } }}
结果:
线程出现的顺序随机,使用了线程yield方法,放弃一直抢夺资源。
=================================
测试代:3:
Thread.sleep():让当前线程休眠指定毫秒数
释放cpu抢占权,和锁旗标的监控权没有关系
public class ThreadDemo3{ public static void main(String[] arg){ Player p1 = new Player("施瓦辛格",1000); Player p2 = new Player("成龙",2000); Player p3 = new Player("李连杰",2500); Player p4 = new Player("史泰龙",3000); p1.start(); p2.start(); p3.start(); p4.start(); System.out.println("开局了"); }}class Player extends Thread{ private String name; private int time; public Player(String name,int time){ this.name = name; this.time=time; } public void run(){ System.out.println(name+"出发了"); try{ Thread.sleep(time); }catch(Exception e){ e.getMessage(); } System.out.println(name+"到了!耗时"+time); }}
结果:
测试代码4:
Thread.join()
当前线程等待指定的线程结束后才能继续进行
public class ThreadDemo3{ public static void main(String[] arg){ Player p1 = new Player("施瓦辛格",1000); Player p2 = new Player("成龙",2000); Player p3 = new Player("李连杰",2500); Player p4 = new Player("史泰龙",3000); p1.start(); p2.start(); p3.start(); p4.start(); try{ p1.join(); p2.join(); p3.join(); p4.join(); }catch(Exception e){ e.getMessage(); } System.out.println("开局了"); }}class Player extends Thread{ private String name; private int time; public Player(String name,int time){ this.name = name; this.time=time; } public void run(){ System.out.println(name+"出发了"); try{ Thread.sleep(time); }catch(Exception e){ e.getMessage(); } System.out.println(name+"到了!耗时"+time); }}
结果:
测试代码5:
public class ThreadDemo3{ public static void main(String[] arg){ Player p4 = new Player("史泰龙",3000); Player p1 = new Player("施瓦辛格",1000); Player p3 = new Player("李连杰",2500); Player p2 = new Player("成龙",2000); p1.start(); p2.start(); p3.start(); p4.start(); try{ p1.join(); p2.join(); p3.join(); p4.join(); }catch(Exception e){ e.getMessage(); } System.out.println("开局了"); }}class Player extends Thread{ private String name; private int time; public Player(String name,int time){ this.name = name; this.time=time; } public void run(){ System.out.println(name+"出发了"); try{ Thread.sleep(time); }catch(Exception e){ e.getMessage(); } System.out.println(name+"到了!耗时"+time); }}
结果:
===============================
daemon:守护,服务员
为其它线程提供服务的线程
若进程中剩余的线程 都是守护线程的话,该线程终止了
Thread.setDaemon(true)
测试代码6:
public class ThreadDemo4{ public static void main(String[] arg){ Box no1 = new Box("no1",3000); Box no2 = new Box("no2",7000); Waiter w = new Waiter(); no1.start(); no2.start(); w.start(); }}//线程1class Box extends Thread{ private String no; private int time; public Box(String no,int time){ this.no = no; this.time=time; } public void run(){ System.out.println(no+"包房开始消费!"); try{ Thread.sleep(time); }catch(Exception e){ e.getMessage(); } System.out.println(no+"包房消费时间:"+time+",结束消费!"); }}//服务员类class Waiter extends Thread{ public void run(){ while(true){ //打印系统当前时间 System.out.println(new java.util.Date()); try{ Thread.sleep(1000); }catch(Exception e){ e.getMessage(); } } }}
结果:
测试代码6:
public class ThreadDemo4{ public static void main(String[] arg){ Box no1 = new Box("no1",3000); Box no2 = new Box("no2",7000); Waiter w = new Waiter(); //设置线程为守护线程 w.setDaemon(true); no1.start(); no2.start(); w.start(); }}//线程1class Box extends Thread{ private String no; private int time; public Box(String no,int time){ this.no = no; this.time=time; } public void run(){ System.out.println(no+"包房开始消费!"); try{ Thread.sleep(time); }catch(Exception e){ e.getMessage(); } System.out.println(no+"包房消费时间:"+time+",结束消费!"); }}//服务员类class Waiter extends Thread{ public void run(){ while(true){ //打印系统当前时间 System.out.println(new java.util.Date()); try{ Thread.sleep(1000); }catch(Exception e){ e.getMessage(); } } }}
结果:
=========================
测试代码7:
减减–操作:原子性操作,不会出现重复
public class ThreadDemo5{ public static void main(String[] arg){ Saler s1 = new Saler("s1"); Saler s2 = new Saler("s2"); s1.start(); s2.start(); }}class Saler extends Thread{ private String name; private static int tickets=100; public Saler(String name){ this.name=name; } public void run(){ while(tickets>0){ System.out.println(name+":"+tickets--); } }}
结果:
测试代码8:
public class ThreadDemo5{ public static void main(String[] arg){ Saler s1 = new Saler("s1"); Saler s2 = new Saler("s2"); s1.start(); s2.start(); }}class Saler extends Thread{ private String name; private static int tickets=100; public Saler(String name){ this.name=name; } public void run(){ while(tickets>0){ int temp = tickets; tickets = tickets-1; System.out.println(name+":"+temp); } }}
结果:
测试代码10:
public class ThreadDemo5{ public static void main(String[] arg){ Saler s1 = new Saler("s1"); Saler s2 = new Saler("s2"); s1.start(); s2.start(); }}class Saler extends Thread{ private String name; private static int tickets=100; public Saler(String name){ this.name=name; } public void run(){ while(tickets>0){ int temp = tickets; System.out.println(name+":"+temp); tickets = tickets-1; } }}
结果:
=======================
线程间通信:共享资源问题
解决办法:加锁,防止并发访问。由并行改为串行。
参照物,锁旗标
测试代码:11:
public class ThreadDemo5{ public static void main(String[] arg){ Saler s1 = new Saler("s1"); Saler s2 = new Saler("s2"); s1.start(); s2.start(); }}class Saler extends Thread{ private String name; static Object lock = new Object(); private static int tickets=100; public Saler(String name){ this.name=name; } public void run(){ while(true){ int t=getTickets(); if(t==-1){ return; }else{ System.out.println(name+":"+t); } } } public int getTickets(){ synchronized(lock){ int temp = tickets; tickets = tickets-1; return temp<1?-1:temp; } }}
结果:加了锁旗标,不会出现重复卖票
==========================
测试代码12:
锁旗标是非静态成员变量时,就不属于类所有,而是对象所拥有。此时的锁是s1、s2自身对象所拥有的锁,并不是同一把锁。
public class ThreadDemo6{ public static void main(String[] arg){ Saler s1 = new Saler("s1"); Saler s2 = new Saler("s2"); s1.start(); s2.start(); }}class Saler extends Thread{ private String name; Object lock = new Object(); private static int tickets=100; public Saler(String name){ this.name=name; } public void run(){ while(true){ int t=getTickets(); if(t==-1){ return; }else{ System.out.println(name+":"+t); } } } public int getTickets(){ synchronized(lock){ int temp = tickets; tickets = tickets-1; return temp<1?-1:temp; } }}
结果:
并没有看出重复卖票的情况,但是并不代表不会出现重复卖票。
测试代码13:
public class ThreadDemo6{ public static void main(String[] arg){ Saler s1 = new Saler("s1"); Saler s2 = new Saler("s2"); s1.start(); s2.start(); }}class Saler extends Thread{ private String name; Object lock = new Object(); private static int tickets=100; public Saler(String name){ this.name=name; } public void run(){ while(true){ int t=getTickets(); if(t==-1){ return; }else{ System.out.println(name+":"+t); } } } public int getTickets(){ synchronized(lock){ int temp = tickets; try{ Thread.sleep(500); }catch(Exception e){} tickets = tickets-1; return temp<1?-1:temp; } }}
结果:
通过睡眠的方式,可以看到此时的结果就出现了重复卖票。
解决办法:必须用同一把锁旗标,通过创建一个对象,每个线程调用该对象。
测试代码14:
public class ThreadDemo6{ public static void main(String[] arg){ Object lock = new Object(); Saler s1 = new Saler("s1",lock); Saler s2 = new Saler("s2",lock); s1.start(); s2.start(); }}class Saler extends Thread{ private String name; Object lock; //Object lock = new Object(); private static int tickets=100; public Saler(String name,Object lock){ this.name=name; this.lock = lock; } public void run(){ while(true){ int t=getTickets(); if(t==-1){ return; }else{ System.out.println(name+":"+t); } } } public int getTickets(){ synchronized(lock){ int temp = tickets; try{ Thread.sleep(50); }catch(Exception e){} tickets = tickets-1; return temp<1?-1:temp; } }}
结果:
此时就不会重新重复卖票。
=================
同步代码块:
synchronized{ ...}
同步代码块执行期间,线程始终持有对象的监控权,其它线程处于阻塞状态。
另一种解决方式:创建卖票池类
测试代码15:
public class ThreadDemo7{ public static void main(String[] arg){ TicketPool pool = new TicketPool(); Saler s1 = new Saler("s1",pool); Saler s2 = new Saler("s2",pool); Saler s3 = new Saler("s3",pool); Saler s4 = new Saler("s4",pool); s1.start(); s2.start(); s3.start(); s4.start(); }}//售票员class Saler extends Thread{ private String name; private TicketPool pool; public Saler(String name,TicketPool pool){ this.name = name; this.pool = pool; } public void run(){ while(true){ int no = pool.getTicket(); if(no==0){ return; } else{ System.out.println(name+":"+no); } } }}class TicketPool{ private int tickets = 100; public int getTicket(){ //同步代码块,以票池本身作为锁旗标 synchronized(this){ int temp = tickets; tickets = tickets-1; return temp>0 ? temp : 0; } }}
结果:
没有出现重复卖票。
变形,方法上锁:
测试代码块16:
public class ThreadDemo7{ public static void main(String[] arg){ TicketPool pool = new TicketPool(); Saler s1 = new Saler("s1",pool); Saler s2 = new Saler("s2",pool); Saler s3 = new Saler("s4",pool); Saler s4 = new Saler("s4",pool); s1.start(); s2.start(); s3.start(); s4.start(); }}//售票员class Saler extends Thread{ private String name; private TicketPool pool; public Saler(String name,TicketPool pool){ this.name = name; this.pool = pool; } public void run(){ while(true){ int no = pool.getTicket(); if(no==0){ return; } else{ System.out.println(name+":"+no); } } }}class TicketPool{ private int tickets = 100; public synchronized int getTicket(){ //同步代码块,以票池本身作为锁旗标 //synchronized(this){ int temp = tickets; tickets = tickets-1; return temp>0 ? temp : 0; //} }}
结果:
这样也是没有问题的。
==========================
7、同步方法是以当前所在对象做锁旗标
synchronized(this)===同步方法
8、同步静态方法,使用类作为同步标记
jvm
*.class加载进入内存的方法区,
public class ThreadDemo7{ public static void main(String[] arg){ TicketPool pool = new TicketPool(); Saler s1 = new Saler("s1"); Saler s2 = new Saler("s2"); Saler s3 = new Saler("s4"); Saler s4 = new Saler("s4"); s1.start(); s2.start(); s3.start(); s4.start(); }}//售票员class Saler extends Thread{ private String name; private TicketPool pool; public Saler(String name){ this.name = name; } public void run(){ while(true){ int no = TicketPool.getTicket(); if(no==0){ return; } else{ System.out.println(name+":"+no); } } }}class TicketPool{ private static int tickets = 100; public static synchronized int getTicket(){ //同步代码块,以票池本身作为锁旗标 //synchronized(this){ int temp = tickets; tickets = tickets-1; return temp>0 ? temp : 0; //} }}
结果:
===========================
9、wait
让当前线程进入锁旗标的等待队列。释放cpu抢占权,还释放锁旗标的监控权