定时器Timer,传统的synchronized

为什么要使用定时器呢?

比如说一个web应用,如果这个应用规模很大,那它的日志数据是不是很多。如果一直存下来服务器的存储量怕是不行吧,需要隔一段时间删除,那么就需要一个线程每隔一段时间去删除日志数据。

package cn.huangwei;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TraditionalTimerTest {
	private static int count = 0;
	public static void main(String[] args) {
		new Timer().schedule(new TimerTask(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				System.out.println("bombing!");
			}
		}, 10000, 3000);//第一次10s炸,接下来每隔3s炸一次
		while(true){
			System.out.println(new Date().getSeconds());
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
		}
	}
}

定时器常用的两种启动方法

通过new Timer().schedule(TimeTask,毫秒值,周期)表示,第一次是过了毫秒值之后,执行TimeTask里面的run方法,接下来

按照每隔周期毫秒执行TimeTask里面的run方法;

通过new Timer().schedule(TimeTask,毫秒值)启动TimeTask里面的run方法,过了毫秒值之后,执行TimeTask里面的run方法,这个timer的任务就结束了。

上面的代码实现了一个功能,每隔两秒、四秒执行TimeTaskrun方法一次,交替两秒与四秒

此处用到的思想就是在TimeTask的run方法里面在定义一个定时器Timer;此处不能使用匿名内部类;因为交替执行需要用到计数器,而如果是匿名内部类,将计数器定义在内部类中,每次计数器都只会重新计数。因此只能定义在外面,而匿名内部类只能访问外部类的final属性,或者可以在外部类中定义成静态变量;代码如下:

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class Test {
	static int count = 0; 
	public static void main(String[] args){
		new Timer().schedule(new TimerTask(){

			@Override
			public void run() {
				// TODO Auto-generated method stub
				Test.count = (Test.count + 1) % 2;
				System.out.println("bombing!");
				new Timer().schedule(new TimerTask(){

					@Override
					public void run() {
						// TODO Auto-generated method stub
						Test.count = (Test.count + 1) % 2;
						System.out.println("bombing!");
						new Timer().schedule(new TimerTask(){

							@Override
							public void run() {
								// TODO Auto-generated method stub
								
							}
							
						}, 2000 + 2000 * count);
					}
					
				}, 2000 + 2000 * count);
			}
			
		}, 2000);
		while(true){
			System.out.println(new Date().getSeconds());
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
		}
	}
}

想要交替不断的运行,就得在每个匿名内部类里面调用一个Timer计时器,而且传入的TimeTask也要嵌套一个Timer定时器,这样无穷无尽,做不下去,重复代码过多;此时可以想到,将匿名内部类TimeTask代码抽取出来,自定义一个TimeTask的的子类;只要在子类中启动一个定时器,new 一个子类的实例,并作为TimeTask传入Timer就会形成一个递归一样的,循环调用的过程,代码如下

package cn.huangwei;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TraditionalTimerTest {
	private static int count = 0;
	public static void main(String[] args) {
		class MyTimerTask extends TimerTask{
			
			@Override
			public void run() {
				count = (count + 1) % 2;
				System.out.println("bombing!");
				new Timer().schedule(new MyTimerTask(), 2000 + 2000 * count);
			}
		}
		new Timer().schedule(new MyTimerTask(), 2000);
		while(true){
			System.out.println(new Date().getSeconds());
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
		}
	}
}

 

2.传统的synchronized

一种同步机制是使用synchronized关键字,这种机制也称为互斥锁机制,这就意味着同一时刻只能有一个线程能够获取到锁,获得的锁也被称为互斥锁。其他需要获取该互斥锁的线程只能被阻塞,直到获取到该锁的线程释放锁。

下面通过一段代码演示synchronized的用法

package cn.huangwei;

public class TraditionalThreadSynchronized {
	public static void main(String[] args) {
		new TraditionalThreadSynchronized().init();
	}
	
	private void init(){
		final Outputer outputer = new Outputer();
		new Thread(new Runnable(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				while(true){
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					outputer.output("zhangxiaoxiang");
				}
			}
		}).start();
		
		new Thread(new Runnable(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				while(true){
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					outputer.output("lihuoming");
				}
			}
		}).start();
	}
	static class Outputer{
		public void output(String name){//或者方法修饰符加synchronized
			int len = name.length();
			synchronized(this){
				for(int i = 0; i < len; i++){
					System.out.print(name.charAt(i));
				}
				System.out.println();
			}
		}
	}
}

该程序的功能是,启动两个线程,一个线程输出“zhangxiaoxiang”,一个字符一个字符输出;另一个线程输出“lihuoming”,也是按字符输出,要求一个线程没输出完成,另一个线程不可输出字符,通过同步机制进行控制;

思想:定义一个输出类Outputer,用于输出给定的字符串,并在输出字符串的方法中,加入同步控制;然后init

方法中,定义Outputer类的实例,由于此处为了方便,线程传入runnable的匿名内部类;在run方法中调用outputer的output方法;这样可以减少一些重复代码;

对于synchronized,找到合适锁对象挺重要的;那么问题来了,判断synchronized的锁对象,决定了同步块的能否实现同步;

public void output(String name){//或者方法修饰符加synchronized
	int len = name.length();
	synchronized(this){
		for(int i = 0; i < len; i++){
			System.out.print(name.charAt(i));
		}
		System.out.println();
	}
}


        public synchronized void output2(String name){
			int len = name.length();
			for(int i = 0; i < len; i++){
				System.out.print(name.charAt(i));
			}
			System.out.println();
		}
		
		public static synchronized void output3(String name){
			int len = name.length();
			for(int i = 0; i < len; i++){
				System.out.print(name.charAt(i));
			}
			System.out.println();
		}

output1和output2这两个方法能互斥嘛?

答案是可以的,因为output2等价于 

		public void output2(String name){
            synchronized(this){
                int len = name.length();
			    for(int i = 0; i < len; i++){
				    System.out.print(name.charAt(i));
			    }
			    System.out.println();
            }
		}

两个方法用的同一个锁对象,可以实现互斥;

那么output3与output犯法能不能互斥?

答案是不行的,因为output里面的this是指调用该方法的对象的实例;而output3是静态方法,他的锁是Outputer.class字节码,锁不一样,不能实现同步;

猜你喜欢

转载自blog.csdn.net/huangwei18351/article/details/81435803