(一)
一、程序 进程 线程
1、程序:指令集 静态概念
2、进程:操作系统 调度程序 动态概念
3、线程:在进程内多条执行路径
(二)
一、继承Thread + run()
启动: 创建子类对象 +对象.start()
package com.zwj.thread; /** * 模拟龟兔赛跑 1、创建多线程 继承 Thread +重写run(线程体) 2、使用线程: 创建子类对象 + 对象.start() 线程启动 * * @author Administrator * */ public class Rabbit extends Thread { @Override public void run() { //线程体 for(int i=0;i<10;i++){ System.out.println("兔子跑了"+i+"步"); } } } class Tortoise extends Thread { @Override public void run() { //线程体 for(int i=0;i<10;i++){ System.out.println("乌龟跑了"+i+"步"); } } }
Rabbit
package com.zwj.thread; public class RabbitApp { /** * @param args */ public static void main(String[] args) { //创建子类对象 Rabbit rab = new Rabbit(); Tortoise tor =new Tortoise(); //调用start 方法 rab.start(); //不要调用run方法 //rab.run(); tor.start(); //tor.run(); for(int i=0;i<10;i++){ System.out.println("main==>"+i); } } } /* 乌龟跑了0步 乌龟跑了1步 兔子跑了0步 乌龟跑了2步 main==>1 乌龟跑了3步 兔子跑了1步 乌龟跑了4步 main==>2 乌龟跑了5步 兔子跑了2步 乌龟跑了6步 main==>3 乌龟跑了7步 兔子跑了3步 乌龟跑了8步 main==>4 乌龟跑了9步 兔子跑了4步 兔子跑了5步 兔子跑了6步 main==>5 兔子跑了7步 main==>6 兔子跑了8步 main==>7 兔子跑了9步 main==>8 main==>9 */
RabbitApp
二、实现Runnable +run()
启动:使用静态代理
1、创建真实角色
2、创建代理角色 Thread+引用
3、代理角色.start()
推荐使用接口:
1、避免单继承局限性
2、便于共享资源
package com.zwj.thread; /** 推荐 Runnable 创建线程 1)、避免单继承的局限性 2)、便于共享资源 使用 Runnable 创建线程 1、类 实现 Runnable接口 +重写 run() -->真实角色类 2、启动多线程 使用静态代理 1)、创建真实角色 2)、创建代理角色 +真实角色引用 3)、调用 .start() 启动线程 * @author Administrator * */ public class Programmer implements Runnable { @Override public void run() { for(int i=0;i<1000;i++){ System.out.println("一边敲helloworld...."); } } }
Programmer
package com.zwj.thread; public class ProgrammerApp { /** * @param args */ public static void main(String[] args) { //1)、创建真实角色 Programmer pro =new Programmer(); //2)、创建代理角色 +真实角色引用 Thread proxy =new Thread(pro); //3)、调用 .start() 启动线程 proxy.start(); for(int i=0;i<10;i++){ System.out.println("一边聊qq...."+i); } } } /* 一边聊qq....0 一边聊qq....1 一边聊qq....2 一边聊qq....3 一边聊qq....4 一边聊qq....5 一边敲helloworld.... 一边敲helloworld.... 一边敲helloworld.... 一边敲helloworld.... 一边敲helloworld.... 一边敲helloworld.... 一边敲helloworld.... 一边敲helloworld.... 一边敲helloworld.... 一边敲helloworld.... 一边聊qq....6 一边聊qq....7 一边聊qq....8 一边聊qq....9*/
ProgrammerApp
package com.zwj.thread; /** * 方便共享资源 * @author Administrator * */ public class Web12306 implements Runnable { private int num =10; @Override public void run() { while(true){ if(num<=0){ break; //跳出循环 } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); } } public static void main(String[] args) { //真实角色 Web12306 web = new Web12306(); //代理 Thread t1 =new Thread(web,"路人甲"); Thread t2 =new Thread(web,"黄牛已"); Thread t3 =new Thread(web,"攻城师"); //启动线程 t1.start(); t2.start(); t3.start(); } }/*路人甲抢到了10 路人甲抢到了8 路人甲抢到了7 路人甲抢到了6 路人甲抢到了5 路人甲抢到了4 路人甲抢到了3 路人甲抢到了2 路人甲抢到了1 黄牛已抢到了9 */
Web12306
三、了解
通过Callable接口实现多线程
优点:可以获取返回值
Callable 和 Future接口
Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。
Callable和Runnable有几点不同:
(1)Callable规定的方法是call(),而Runnable规定的方法是run().
(2)call()方法可抛出异常,而run()方法是不能抛出异常的。
(3) Callable的任务执行后可返回值,运行Callable任务可拿到一个Future对象,而Runnable的任务是不能返回值的。
Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。
通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。
缺点 :繁琐
思路:
1)、创建 Callable实现类+重写call
2)、借助 执行调度服务 ExecutorService,获取Future对象
ExecutorService ser=Executors.newFixedThreadPool(2);
Future result =ser.submit(实现类对象)
3)、获取值 result.get()
4 )、 停止服务 ser.shutdownNow();
package com.zwj.thread; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * 使用Callable创建线程 * @author Administrator * */ public class Call { public static void main(String[] args) throws InterruptedException, ExecutionException { //创建线程 ExecutorService ser=Executors.newFixedThreadPool(2); Race tortoise = new Race("老不死",1000); Race rabbit = new Race("小兔子",500); //获取值 Future<Integer> result1 =ser.submit(tortoise) ; Future<Integer> result2 =ser.submit(rabbit) ; Thread.sleep(2000); //2秒 tortoise.setFlag(false); //停止线程体循环 rabbit.setFlag(false); int num1 =result1.get(); int num2 =result2.get(); System.out.println("乌龟跑了-->"+num1+"步"); System.out.println("小兔子跑了-->"+num2+"步"); //停止服务 ser.shutdownNow(); } } class Race implements Callable<Integer>{ private String name ; //名称 private long time; //延时时间 private boolean flag =true; private int step =0; //步 public Race() { } public Race(String name) { super(); this.name = name; } public Race(String name,long time) { super(); this.name = name; this.time =time; } @Override public Integer call() throws Exception { while(flag){ Thread.sleep(time); //延时 step++; } return step; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getTime() { return time; } public void setTime(long time) { this.time = time; } public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } public int getStep() { return step; } public void setStep(int step) { this.step = step; } } /*乌龟跑了-->3步 小兔子跑了-->5步 */
Call
(三)
1.新建状态(New):
当用new操作符创建一个线程时, 例如new Thread(r),线程还没有开始运行,此时线程处在新建状态。 当一个线程处于新生状态时,程序还没有开始运行线程中的代码
2.就绪状态(Runnable)
一个新创建的线程并不自动开始运行,要执行线程,必须调用线程的start()方法。当线程对象调用start()方法即启动了线程,start()方法创建线程运行的系统资源,并调度线程运行run()方法。当start()方法返回后,线程就处于就绪状态。
处于就绪状态的线程并不一定立即运行run()方法,线程还必须同其他线程竞争CPU时间,只有获得CPU时间才可以运行线程。因为在单CPU的计算机系统中,不可能同时运行多个线程,一个时刻仅有一个线程处于运行状态。因此此时可能有多个线程处于就绪状态。对多个处于就绪状态的线程是由Java运行时系统的线程调度程序(thread scheduler)来调度的。
3.运行状态(Running)
当线程获得CPU时间后,它才进入运行状态,真正开始执行run()方法.
4. 阻塞状态(Blocked)
线程运行过程中,可能由于各种原因进入阻塞状态:
1>线程通过调用sleep方法进入睡眠状态;
2>线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者;
3>线程试图得到一个锁,而该锁正被其他线程持有;
4>线程在等待某个触发条件;
……
所谓阻塞状态是正在运行的线程没有运行结束,暂时让出CPU,这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。
5. 死亡状态(Dead)
有两个原因会导致线程死亡:
1) run方法正常退出而自然死亡,
2) 一个未捕获的异常终止了run方法而使线程猝死。
为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法。如果是可运行或被阻塞,这个方法返回true; 如果线程仍旧是new状态且不是 可运行的, 或者线程死亡了,则返回false.
二、停止线程
1、自然终止:线程体正常执行完毕
2、外部干涉:
1)、线程类中 定义 线程体使用的标识
2)、线程体使用该标识
3)、提供对外的方法改变该标识
4)、外部根据条件调用该方法即可
package com.zwj.status; public class StopDemo01 { /** * @param args */ public static void main(String[] args) { Study s =new Study(); new Thread(s).start(); //外部干涉 当main线程执行50次时,study线程停止运行 for(int i=0;i<100;i++){ if(50==i){ //外部干涉 s.stop(); } System.out.println("main.....-->"+i); } } } class Study implements Runnable{ //1)、线程类中 定义 线程体使用的标识 private boolean flag =true; @Override public void run() { //2)、线程体使用该标识 while(flag){ System.out.println("study thread...."); } } //3)、对外提供方法改变标识 public void stop(){ this.flag =false; } }
StopDemo01
三、阻塞
1、join :合并线程, join()方法使调用该方法的线程在此之前执行完毕,也就是等待该方法的线程执行完毕后再往下继续执行。注意该方法也需要捕捉异常。
package com.zwj.status; /** * join:合并线程 * @author Administrator * */ public class JoinDemo01 extends Thread { /** * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { JoinDemo01 demo = new JoinDemo01(); Thread t = new Thread(demo); //新生 t.start();//就绪 //cpu调度 运行 for(int i=0;i<10;i++){ if(5==i){ t.join(); //执行JoinDemo01线程 main线程等待上一个线程执行完后在执行... } System.out.println("main...."+i); } } @Override public void run() { for(int i=0;i<10;i++){ System.out.println("join...."+i); } } } /*main....0 join....0 main....1 join....1 main....2 join....2 main....3 main....4 join....3 join....4 join....5 join....6 join....7 join....8 join....9 main....5 main....6 main....7 main....8 main....9 */
JoinDemo01
2、yield:暂停自己的线程 static, 该方法与sleep()类似,只是不能由用户指定暂停多长时间,并且yield()方法只能让同优先级的线程有执行的机会。
package com.bjsxt.thread.status; public class YieldDemo01 extends Thread { /** * @param args */ public static void main(String[] args) { YieldDemo01 demo = new YieldDemo01(); Thread t = new Thread(demo); //新生 t.start();//就绪 //cpu调度 运行 for(int i=0;i<1000;i++){ if(i%20==0){ //暂停本线程 main Thread.yield(); } System.out.println("main...."+i); } } @Override public void run() { for(int i=0;i<1000;i++){ System.out.println("yield...."+i); } } }
YieldDemo01
3、sleep:休眠,不释放锁
1)、与时间相关:倒计时
2)、模拟网络延时
3)、使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁。也就是说如果有synchronized同步快,其他线程仍然不能访问共享数据。注意该方法要捕捉异常。
package com.zwj.status; import java.text.SimpleDateFormat; import java.util.Date; /** * 倒计时 * 1、倒数10个数,一秒内打印一个 * 2、倒计时 * @author Administrator * */ public class SleepDemo01 { /** * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { test1(); Date endTime =new Date(System.currentTimeMillis()+10*1000); long end =endTime.getTime(); while(true){ //输出 System.out.println(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(endTime)); //等待一秒 Thread.sleep(1000); //构建下一秒时间 endTime =new Date(endTime.getTime()-1000); //10秒以内 继续 否则 退出 if(end-10000>endTime.getTime()){ break; } } } /*倒计时 10 */ public static void test1() throws InterruptedException{ int num =10; while(true){ System.out.println(num--); Thread.sleep(1000); //暂停 1000毫秒等于1秒 if(num<=0){ break; } } } /*10 9 8 7 6 5 4 3 2 1 2017-11-12 12:46:38 2017-11-12 12:46:37 2017-11-12 12:46:36 2017-11-12 12:46:35 2017-11-12 12:46:34 2017-11-12 12:46:33 2017-11-12 12:46:32 2017-11-12 12:46:31 2017-11-12 12:46:30 2017-11-12 12:46:29 2017-11-12 12:46:28*/ }
SleepDemo01
package com.zwj.status; /** * Sleep模拟 网络延时 线程不安全的类 * @author Administrator * */ public class SleepDemo02 { /** * @param args */ public static void main(String[] args) { //真实角色 Web12306 web= new Web12306(); Web12306 web2 = new Web12306(); //代理 Thread t1 =new Thread(web,"路人甲"); Thread t2 =new Thread(web,"黄牛已"); Thread t3 =new Thread(web,"攻城师"); //启动线程 t1.start(); t2.start(); t3.start(); } } class Web12306 implements Runnable { private int num =10; @Override public void run() { while(true){ if(num<=0){ break; //跳出循环 } try { //500毫秒 Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); } } } /*黄牛已抢到了10 路人甲抢到了9 攻城师抢到了8 路人甲抢到了7 黄牛已抢到了6 攻城师抢到了5 黄牛已抢到了4 路人甲抢到了3 攻城师抢到了2 黄牛已抢到了0 路人甲抢到了1 攻城师抢到了-1*/
SleepDemo02
(四)
同步:并发 多个线程访问同一份资源 确保资源安全 –>线程安全
synchronized –>同步
一、同步块
synchronized(引用类型|this|类.class){
}
二、同步方法
synchronized
三、死锁: 过多的同步容易造成死锁
package com.zwj.synchronizeds; public class SynDemo01 { /** * @param args */ public static void main(String[] args) { //真实角色 Web12306 web= new Web12306(); //代理 Thread t1 =new Thread(web,"路人甲"); Thread t2 =new Thread(web,"黄牛已"); Thread t3 =new Thread(web,"攻城师"); //启动线程 t1.start(); t2.start(); t3.start(); } } /** * 线程安全的类 * @author Administrator * */ class Web12306 implements Runnable { private int num =10; private boolean flag =true; @Override public void run() { while(flag){ //test5(); test4(); //test3(); 线程安全 锁定正确 同步代码块 //test2(); 线程安全 锁定正确 同步方法 static synchronized //test1(); 线程不安全 } } public void test6(){ if(num<=0){ flag=false; //跳出循环 return ; } //a b c synchronized(this){ try { Thread.sleep(500); //模拟 延时 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); } } //线程不安全 锁定资源不正确 public void test5(){ //a b c synchronized((Integer)num){ if(num<=0){ flag=false; //跳出循环 return ; } try { Thread.sleep(500); //模拟 延时 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); } } //锁定范围不正确 线程不安全 public void test4(){ // c 1 synchronized(this){ //b if(num<=0){ flag=false; //跳出循环 return ; } } // b try { Thread.sleep(500); //模拟 延时 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); }//a -->1 //线程安全 锁定正确 同步代码块 public void test3(){ //a b c synchronized(this){ if(num<=0){ flag=false; //跳出循环 return ; } try { Thread.sleep(500); //模拟 延时 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); } } //线程安全 锁定正确 同步方法 static synchronized public synchronized void test2(){ if(num<=0){ flag=false; //跳出循环 return ; } try { Thread.sleep(500); //模拟 延时 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); } //线程不安全 public void test1(){ if(num<=0){ flag=false; //跳出循环 return ; } try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); } }
SynDemo01
package com.zwj.synchronizeds; /** * 单例创建的方式 * 1、懒汉式 * 1)、构造器私有化 * 2)、声明私有的静态属性 * 3)、对外提供访问属性的静态方法,确保该对象存在 * * @author Administrator * */ public class MyJvm { private static MyJvm instance; private MyJvm(){ } public static MyJvm getInstance (){ if(null==instance){ //提供效率 synchronized(MyJvm.class){ if(null==instance){ //安全 instance =new MyJvm(); } } } return instance; } } /** * 饿汉式 1)、构造器私有化 * 2)、声明私有的静态属性,同时创建该对象 * 3)、对外提供访问属性的静态方法 * @author Administrator * */ class MyJvm2 { private static MyJvm2 instance =new MyJvm2(); private MyJvm2(){ } public static MyJvm2 getInstance (){ return instance; } } /** * 类在使用的时候加载 ,延缓加载时间 * @author Administrator * */ class MyJvm3 { private static class JVMholder{ private static MyJvm3 instance =new MyJvm3(); } private MyJvm3(){ } //不调用此方法就不会加载jvmholder静态内部类 public static MyJvm3 getInstance (){ return JVMholder.instance; } }
MyJvm
package com.zwj.synchronizeds; /** * 单例设计模式:确保一个类只有一个对象 * @author Administrator * */ public class SynDemo02 { /** * @param args */ public static void main(String[] args) { JvmThread thread1 = new JvmThread(100); JvmThread thread2 = new JvmThread(500); thread1.start(); thread2.start(); } } class JvmThread extends Thread{ private long time; public JvmThread() { } public JvmThread(long time) { this.time =time; } @Override public void run() { System.out.println(Thread.currentThread().getName()+"-->创建:"+Jvm.getInstance(time)); } } /** * 单例设计模式 * 确保一个类只有一个对象 * 懒汉式 double checking * 1、构造器私有化,避免外部直接创建对象 * 2、声明一个私有的静态变量 * 3、创建一个对外的公共的静态方法 访问该变量,如果变量没有对象,创建该对象 */ class Jvm { //声明一个私有的静态变量 private static Jvm instance =null; //构造器私有化,避免外部直接创建对象 private Jvm(){ } //创建一个对外的公共的静态方法 访问该变量,如果变量没有对象,创建该对象 public static Jvm getInstance(long time){ // c d e -->效率 提供 已经存在对象的访问效率 if(null==instance){ // a b synchronized(Jvm.class){ if(null==instance ){ try { Thread.sleep(time); //延时 ,放大错误 } catch (InterruptedException e) { e.printStackTrace(); } instance =new Jvm(); } } }//a return instance; } public static Jvm getInstance3(long time){ //a b c d e -->效率不高 c 存在对象也需要等待 synchronized(Jvm.class){ if(null==instance ){ try { Thread.sleep(time); //延时 ,放大错误 } catch (InterruptedException e) { e.printStackTrace(); } instance =new Jvm(); } return instance; } } public static synchronized Jvm getInstance2(long time){ if(null==instance ){ try { Thread.sleep(time); //延时 ,放大错误 } catch (InterruptedException e) { e.printStackTrace(); } instance =new Jvm(); } return instance; } public static Jvm getInstance1(long time){ if(null==instance ){ try { Thread.sleep(time); //延时 ,放大错误 } catch (InterruptedException e) { e.printStackTrace(); } instance =new Jvm(); } return instance; } }
SynDemo02
package com.zwj.synchronizeds; /** * 过多的同步方法可能造成死锁 * @author Administrator * */ public class SynDemo03 { /** * @param args */ public static void main(String[] args) { Object g =new Object(); Object m = new Object(); Test t1 =new Test(g,m); Test2 t2 = new Test2(g,m); Thread proxy = new Thread(t1); Thread proxy2 = new Thread(t2); proxy.start(); proxy2.start(); } } class Test implements Runnable{ Object goods ; Object money ; public Test(Object goods, Object money) { super(); this.goods = goods; this.money = money; } @Override public void run() { while(true){ test(); } } public void test(){ synchronized(goods){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized(money){ } } System.out.println("一手给钱"); } } class Test2 implements Runnable{ Object goods ; Object money ; public Test2(Object goods, Object money) { super(); this.goods = goods; this.money = money; } @Override public void run() { while(true){ test(); } } public void test(){ synchronized(money){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized(goods){ } } System.out.println("一手给货"); } }
SynDemo03
(五)
信号灯法
一、 wait() :等待,释放锁 sleep 不释放锁
二、notify()/notifyAll():唤醒
与 synchronized 一起使用
package com.zwj.pro; /** 一个场景,共同的资源 生产者消费者模式 信号灯法 wait() :等待,释放锁 sleep 不释放锁 notify()/notifyAll():唤醒 与 synchronized * @author Administrator * */ public class Movie { private String pic ; //信号灯 //flag -->T 生产生产,消费者等待 ,生产完成后通知消费 //flag -->F 消费者消费 生产者等待, 消费完成后通知生产 private boolean flag =true; /** * 播放 * @param pic */ public synchronized void play(String pic){ if(!flag){ //生产者等待 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //开始生产 try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("生产了:"+pic); //生产完毕 this.pic =pic; //通知消费 this.notify(); //生产者停下 this.flag =false; } public synchronized void watch(){ if(flag){ //消费者等待 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //开始消费 try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("消费了"+pic); //消费完毕 //通知生产 this.notifyAll(); //消费停止 this.flag=true; } }
Movie
package com.zwj.pro; /** * 生产者 * @author Administrator * */ public class Player implements Runnable { private Movie m ; public Player(Movie m) { super(); this.m = m; } @Override public void run() { for(int i=0;i<20;i++){ if(0==i%2){ m.play("左青龙"+i); }else{ m.play("右白虎"+i); } } } }
Player
package com.zwj.pro; public class Watcher implements Runnable { private Movie m ; public Watcher(Movie m) { super(); this.m = m; } @Override public void run() { for(int i=0;i<20;i++){ m.watch(); } } }
Watcher
package com.zwj.pro; public class App { public static void main(String[] args) { //共同的资源 Movie m = new Movie(); //多线程 Player p = new Player(m); Watcher w = new Watcher(m); new Thread(p).start(); new Thread(w).start(); } } /*生产了:左青龙0 消费了左青龙0 生产了:右白虎1 消费了右白虎1 生产了:左青龙2 消费了左青龙2 生产了:右白虎3 消费了右白虎3 生产了:左青龙4 消费了左青龙4 生产了:右白虎5 消费了右白虎5 生产了:左青龙6 消费了左青龙6 生产了:右白虎7*/
App
package com.zwj.pro; public class TestProduce { public static void main(String[] args) { SyncStack sStack = new SyncStack(); Shengchan sc = new Shengchan(sStack); Xiaofei xf = new Xiaofei(sStack); sc.start(); xf.start(); } } class Mantou { int id; Mantou(int id){ this.id=id; } } class SyncStack{ int index=0; Mantou[] ms = new Mantou[10]; public synchronized void push(Mantou m){ while(index==ms.length){ try { this.wait(); //wait后,线程会将持有的锁释放。sleep是即使睡着也持有互斥锁。 } catch (InterruptedException e) { e.printStackTrace(); } } this.notify(); //唤醒在当前对象等待池中等待的第一个线程。notifyAll叫醒所有在当前对象等待池中等待的所有线程。 //如果不唤醒的话。以后这两个线程都会进入等待线程,没有人唤醒。 ms[index]=m; index++; } public synchronized Mantou pop(){ while(index==0){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.notify(); index--; return ms[index]; } } class Shengchan extends Thread{ SyncStack ss = null; public Shengchan(SyncStack ss) { this.ss=ss; } @Override public void run() { for (int i = 0; i < 20; i++) { System.out.println("造馒头:"+i); Mantou m = new Mantou(i); ss.push(m); } } } class Xiaofei extends Thread{ SyncStack ss = null; public Xiaofei(SyncStack ss) { this.ss=ss; } @Override public void run() { for (int i = 0; i < 20; i++) { Mantou m = ss.pop(); System.out.println("吃馒头:"+i); } } }
TestProduce
(六)
了解
Timer()
schedule(TimerTask task, Date time)
schedule(TimerTask task, Date firstTime, long period)
自学 juc quartz
package com.zwj.pro; import java.util.Date; import java.util.Timer; import java.util.TimerTask; /** 了解 Timer() schedule(TimerTask task, Date time) schedule(TimerTask task, Date firstTime, long period) 自学 quartz * @author Administrator * */ public class TimeDemo01 { /** * @param args */ public static void main(String[] args) { Timer timer =new Timer(); //从new Date(System.currentTimeMillis()+1000)开始执行200次 timer.schedule(new TimerTask(){ @Override public void run() { System.out.println("so easy...."); }}, new Date(System.currentTimeMillis()+1000), 200); } }
TimeDemo01