最近公司给我提供了一台全新的服务器,要求把旧服务器上的java程序转移到新服务器。这里记录一下安装JAVA环境以及后面遇到的一个小问题。
首先需要去官方网站下载JDK安装包,官网地址https://www.oracle.com/java/technologies/downloads,我选择的是jdk-8u321-linux-x64.tar.gz,将下载后的JDK源码包上传到linux服务器,放在/usr/local/src目录,解压并移动到/usr/local,tar -zxvf jdk-8u321-linux-x64.tar.gz -C /usr/local,编辑/etc/profile配置文件,在文件最下方添加环境变量
export JAVA_HOME=/usr/local/jdk1.8.0_321
export JRE_HOME=${JAVA_HOME}
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH
执行source /etc/profile ,使配置文件生效,最后java -version验证JDK是否安装已经装好了。
JDK装好后我遇到另外一个问题,当直接使用java命令启动一个java程序时是完全OK的,但是将这个命令放在crontab里面定时执行的时候却没有起作用,刚开始我怀疑是定时没有生效,后来用service crond status 查看定时的开启状态和执行日志,执行记录显示当执行到java任务时,系统无法识别java命令。
通过日志可以看到定时是生效了,但是crontab里面没有识别到java命令,查询资料后才知道,有些linux环境的shell脚本里面无法获取我们在/etc/profile里设置的环境变量,而crontab可以视为一种特殊的shell脚本,于是我用crontab -e 更改了定时任务的命令行,在java命令前面加上 source /etc/profile; 指定我要使用的配置文件
再来看执行日志:
还是有问题,这应该是.class文件的路径写法不对,继续改,用 -cp 指定路径,后面再接包名
再看日志,总算是正常了
理论上到这一步java在linux上的定时就算成功部署了,但是这里需要考虑一个问题,我们的任务执行一次可能要很长的时间,如果下一次定时任务开始执行的时候上一次的任务尚未执行完毕该怎么办?于是需要给定时任务加上一把“锁”,当上一次任务尚未执行完毕时,本次任务因无法获得锁而不执行。
*/2 * * * * source /etc/profile; flock -xn /root/download/MessageDemo.lock java -cp /root/download/ com.chengya.demo.test.MessageDemo >> /root/download/MessageDemo.log 2>&1
但是这样依然有风险,如果某次任务在执行过程中发生阻塞,会使这个阻塞的任务一直占有锁,导致后面的定时永远无法执行,因此需要设置超时时间,比如设置超时时间为60秒,即单次任务最长执行时间为60秒,如果60秒还没结束,则强制杀死此次任务。
*/2 * * * * source /etc/profile; flock -xn /root/download/MessageDemo.lock timeout 60 java -cp /root/download/ com.chengya.demo.test.MessageDemo >> /root/download/MessageDemo.log 2>&1
注意:如果java代码中有包路径,一定要将编译后的.class文件放在包路径里面,使用java命令执行.class文件时,包路径之间用 . 隔开,而不是 / ,且不用写文件名的.class后缀,否则会报“找不到或无法加载主类”的错误。
我的java源代码:
import java.text.SimpleDateFormat; import java.util.Date; public class MessageDemo { public static void main(String[] args) { System.out.println(String.format("%s step01 start",currentTime())); System.out.println(String.format("%s step02 end",currentTime())); } public static String currentTime() { Date date = new Date(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return dateFormat.format(date); } }