博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java 线程编程中的同步、重复、定时
阅读量:4125 次
发布时间:2019-05-25

本文共 7101 字,大约阅读时间需要 23 分钟。

(一)线程同步

实现生产者消费者问题来说明线程问题,举例如下所示:

/** * 生产者消费者问题 */ public class ProducerConsumer { /** * 主方法 */ public static void main(String[] args) { ProductBox pb = new ProductBox(); Producer p = new Producer(pb); Consumer c = new Consumer(pb); //根据消费者、生产者生成线程 Thread pThread = new Thread(p); Thread cThread = new Thread(c); pThread.setPriority(Thread.MAX_PRIORITY); pThread.start(); cThread.start(); } } /** * 产品对象 * @author johsnton678 */ class Product { int id; public Product(int id) { super(); this.id = id; } public String toString(){ return "Product:" + id; } } /** * 产品盒对象 * @author johnston678 */ class ProductBox { Product[] productbox = new Product[6]; int index = 0; public ProductBox() { super(); } //存入方法,将产品存入产品盒 public synchronized void push(Product p) { //判断产品是否超出产品盒的最大容量,如果超出中则等待 while (index == productbox.length) { try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } this.notify(); productbox[index] = p; index ++; } //取出操作 public synchronized Product pop() { //如果产品数量为零,这等待 while (index == 0) { try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } this.notify(); index --; return productbox[index]; } } /** * 生产者 * @author johnston678 */ class Producer implements Runnable { ProductBox productbox = null; public Producer(ProductBox productbox) { super(); this.productbox = productbox; } @Override public void run() { // TODO Auto-generated method stub for (int i=0; i<10; i++) { Product p = new Product(i); productbox.push(p); System.out.println("produce:" + p); try { Thread.sleep((int)(Math.random() * 200)); } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * 消费者 * */ class Consumer implements Runnable { ProductBox productbox = null; public Consumer(ProductBox productbox) { super(); this.productbox = productbox; } @Override public void run() { // TODO Auto-generated method stub for (int i=0; i<10; i++) { Product p = productbox.pop(); System.out.println("consume:" + p); try { Thread.sleep((int)(Math.random() * 1000)); } catch (InterruptedException e) { e.printStackTrace(); } } } }

其中需要注意的是java多线程之 wait(),notify(),notifyAll()方法:

wait(),notify(),notifyAll()不属于Thread类,而是属于Object基础类,也就是说每个对像都有wait(),notify(),notifyAll()

的功能.因为都个对像都有锁,锁是每个对像的基础,当然操作锁的方法也是最基础了.
先看java doc怎么说:
wait导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。当前的线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行.

notify唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。直到当前的线程放弃此对象上的锁定,才能继续执行被唤醒的线程。此方法只应由作为此对象监视器的所有者的线程来调用.

"当前的线程必须拥有此对象监视器"与"此方法只应由作为此对象监视器的所有者的线程来调用"说明wait方法与notify方法必须在同步块内执行,即synchronized(obj之内).

调用对像wait方法后,当前线程释放对像锁,进入等待状态.直到其他线程(也只能是其他线程)通过notify 方法,或 notifyAll.该线程重新获得对像锁.

继续执行,记得线程必须重新获得对像锁才能继续执行.因为synchronized代码块内没有锁是寸步不能走的,可以写成public synchronized void push(Product p) { ..... this.wait(); } 或者是 public synchronized void push(Product p) { ..... synchronized(this){ this.wait(); } }

(二)线程的定时执行:

会用到java.util.Calendar和java.util.timer类,

1.java.util.Calendar用来设定时间,java.util.timer定时执行

Calendar c = Calendar.getInstance();得到calendar类,

c.setTime(Date)设定时间,或是c.set(year,month,day,hour,m,s);注意,显示的月份比真实事件多一个月,我们设定时要比真实时间剪掉一个月如:现在是5月,我们定时的时候要写4

2.

Timer time = new Timer();

Integer a = new Integer(0) ;
MyTime t = new MyTime();//继承自TimerTask类,实现了run()方法,其中是日期的比较
//一秒后执行,每5秒执行一次
time.schedule(t, 1000,5000);

package thread; import java.util.Calendar; import java.util.Date; import java.util.Timer; import java.util.TimerTask; //数据类1 class Data1{ private static int age = 0; public static int getAge() { return age; } public static void setAge(int age) { Data1.age = age; } } //数据类2 class Data2{ private static int age = 0; public static int getAge() { return age; } public static void setAge(int age) { Data2.age = age; } } class T1 extends Thread{ @Override public void run(){ for (int i = 0; i < 100; i++) { System.out.println(); System.out.println("1 的年龄 :" + i); Data1.setAge(i); try { this.sleep(500); } catch (InterruptedException e) { } } } } class T2 extends Thread{ @Override public void run() { for (int i = 110; i < 11000; i++) { System.out.println("2 的年龄 :" + i); Data2.setAge(i); try { this.sleep(500); } catch (InterruptedException e) { } } } } class T3 extends Thread{ @Override public void run() { Timer time = new Timer(); Integer a = new Integer(0) ; MyTime t = new MyTime(); //一秒后执行,每5秒执行一次 time.schedule(t, 1000,5000); } } /** * 定时执行类,时间到后执行操作 * @author WangQun * */ class MyTime extends TimerTask{ @Override public void run() { // 质检 Calendar c = Calendar.getInstance(); Date date =new Date();//设置当前日期 c.set(2010, 04, 17, 10,19);//设置定时时间 System.out.println("当前时间 : "+date); System.out.println("设定时间 : "+c.getTime()); //比较时间 if(date.compareTo(c.getTime()) < 0){ System.out.println("时间还没到!"); }else if(date.compareTo(c.getTime()) == 0){ System.out.println("时间到了!"); }else if(date.compareTo(c.getTime()) > 0){ System.out.println("时间过了!"); } } } class ShangSu{ public static void main(String[] args)throws InterruptedException{ T3 t3 = new T3(); } }

3.time定时器的关闭

如果你使用的是JDK 5+,还有一个scheduleAtFixedRate模式可以用,在这个模式下,Timer会尽量的让任务在一个固定的频率下运行,举例说明:在上面的例子中,我们想让MyTask在1秒钟后,每两秒钟执行一次,但是因为java不是实时的(其实java实时性很差.....),所以,我们在上个程序中表达的原义并不能够严格执行.如果我们调用的是scheduleAtFixedRate,那么,Timer会尽量让你的Task执行的频率保持在2秒一次.运行上面的程序,假设使用的是scheduleAtFixedRate,那么下面的场景就是可能的:1秒钟后,MyTask执行一次,因为系统繁忙,之后的2.5秒后MyTask才得以执行第二次,然后,Timer记下了这个延迟,并尝试在下一个任务的时候弥补这个延迟,那么,1.5秒后,MyTask将执行的三次."以固定的频率而不是固定的延迟时间去执行一个任务"

package thread; import java.io.IOException; import java.util.Timer; /**//* * 本类给出了使用Timer和TimerTaske的主要方法,其中包括定制任务,添加任务 * 退出任务,退出定时器. * 因为TimerTask的status域是包级可访问的,所以没有办法在java.util.包外 * 得到其状态,这对编程造成一些不便 .我们不能判断某个Task的状态了. * */ public class T { public static void main(String[] args){ Timer timer = new Timer(); MyTask myTask1 = new MyTask("myTask-1"); MyTask myTask2 = new MyTask("myTask-2"); timer.schedule(myTask1, 1000, 2000); timer.scheduleAtFixedRate(myTask2, 2000, 3000); while (true){ try { byte[] info = new byte[1024]; int len = System.in.read(info); String strInfo = new String(info, 0, len, "GBK");//从控制台读出信息 System.out.println("strInfo:"+strInfo); if (strInfo.charAt(strInfo.length() - 1) == ' ') { strInfo = strInfo.substring(0, strInfo.length() - 2); } if (strInfo.startsWith("Cancel-1")) { myTask1.cancel();//退出单个任务 // 其实应该在这里判断myTask2是否也退出了,是的话就应该break.但是因为无法在包外得到 // myTask2的状态,所以,这里不能做出是否退出循环的判断. } else if (strInfo.startsWith("Cancel-2")) { myTask2.cancel(); } else if (strInfo.startsWith("Cancel-All")) { timer.cancel();//退出Timer break; } else { // 只对myTask1作出判断,偷个懒^_^ myTask1.setInfo("myTask-1"); myTask2.setInfo("myTask-2"); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } static class MyTask extends java.util.TimerTask { String info = "^_^"; public MyTask(String info) { this.info = info; } @Override public void run() { // TODO Auto-generated method stub System.out.println(info); } public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } } }

果然很方便吧^_^

下面给出一个复杂点的例子,其中告诉大家怎么退出单个TimerTask,怎么退出所有Task

转载地址:http://xtlpi.baihongyu.com/

你可能感兴趣的文章
hdu 3787 hdoj 3787
查看>>
hdu 3790 hdoj 3790
查看>>
hdu 3789 hdoj 3789
查看>>
hdu 3788 hdoj 3788
查看>>
zju 1003 zoj 1003
查看>>
zju 1004 zoj 1004
查看>>
zju 1005 zoj 1005
查看>>
zju 1006 zoj 1006
查看>>
【虚拟机】虚拟化架构与系统部署(Windows系统安装)
查看>>
字节跳动安卓开发实习生面试分享
查看>>
好书分享之——《能力陷进》
查看>>
阅读笔记《c++ primer》
查看>>
阅读笔记《C++标准程序库》
查看>>
基于mirror driver的windows屏幕录像
查看>>
C语言8
查看>>
Qt实现简单延时
查看>>
qml有关矩形说明
查看>>
在qt中使用QSplitter设置初始比例setStretchFactor失效的解决方法
查看>>
repeater的使用
查看>>
qt msvc编译中文乱码解决
查看>>