十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
1、java多线程调用同步方法时主程序或者后台服务Service程序两者必须有一个正在运行着,定时任务才会执行。
成都创新互联公司主打移动网站、做网站、成都网站设计、网站改版、网络推广、网站维护、域名申请、等互联网信息服务,为各行业提供服务。在技术实力的保障下,我们为客户承诺稳定,放心的服务,根据网站的内容与功能再决定采用什么样的设计。最后,要实现符合网站需求的内容、功能与设计,我们还会规划稳定安全的技术方案做保障。
2、自动执行的任务可以设置开启或关闭定时,检查任务的这一开关处于开启状态。
3、源目录在定时的时间点如果没有变化,任务执行后不会留下日志,通过查看任务的最后执行时间确定任务到底执行了没有。
4、执行失败和没有执行不是同一回事,如果是执行失败则要分析失败原因。这是java多线程调用同步方法时,休眠后代码执行不到的原因。
这个要分段来实现, 第一步是让线程同步,第二部是让线程有顺序。
同步:我们可以用synchronized来解决。
Java线程同步原理: java会为每个object对象分配一个monitor,当某个对象的同步方法(synchronized methods )被多个线程调用时,该对象的monitor将负责处理这些访问的并发独占要求。
当一个线程调用一个对象的同步方法时,JVM会检查该对象的monitor。如果monitor没有被占用,那么这个线程就得到了monitor的占有权,可以继续执行该对象的同步方法;如果monitor被其他线程所占用,那么该线程将被挂起,直到monitor被释放。
当线程退出同步方法调用时,该线程会释放monitor,这将允许其他等待的线程获得monitor以使对同步方法的调用执行下去。就像下面这样:
public void test() {
synchronized (this) {
//做一些事
//这里只会有一个线程来调用该方法,因为只有一个this对象作为资源分配给该线程
}
}
顺序:我们可以用List来解决,因为它是有序的。我们只需要将要执行的线程放入到List中
上代码:
/**
* 让多个线程同步顺序执行的线程管理器
* @author bianrx
* @date 2012.1.18
* SynchronizedRunMultiThread
*/
public class SyncManager {
/**
* 待执行的线程集合,注意这里必须是Runnable接口类型,下面会解释
*/
private ListRunnable runnableList;
public SyncManager(){}
public SyncManager(ListRunnable runnableList) {
this.runnableList = runnableList;
}
public void setRunnable(ListRunnable runnableList) {
this.runnableList = runnableList;
}
public void run() {
//遍历代执行的线程集合
for(Runnable runnable: runnableList) {
runThread(runnable);
}
}
/**
* 按顺序同步执行多个线程
* @author bianrx
* @date 2012.1.18
* @param runnable
*/
private void runThread(Runnable runnable) {
synchronized (this) {
runnable.run();//这里需要注意的是:必须调用run方法,因为如果你调用了start方法,线程只会向JVM请求资源,但是未必就执行其中的run。
//这个方法是同步的,所以当前只有一个线程占用了this对象。
}
}
}
在Java中一共有四种方法支持同步,其中前三个是同步方法,一个是管道方法。管道方法不建议使用。
wait()/notify()方法
await()/signal()方法
BlockingQueue阻塞队列方法
PipedInputStream/PipedOutputStream
阻塞队列的一个简单实现:
public class BlockingQueue {
private List queue = new LinkedList();
private int limit = 10;
public BlockingQueue(int limit){
this.limit = limit;
}
public synchronized void enqueue(Object item)throws InterruptedException {
while(this.queue.size() == this.limit) {
wait();
}
if(this.queue.size() == 0) {
notifyAll();
}
this.queue.add(item);
}
public synchronized Object dequeue() throws InterruptedException{
while(this.queue.size() == 0){
wait();
}
if(this.queue.size() == this.limit){
notifyAll();
}
return this.queue.remove(0);
}}
在enqueue和dequeue方法内部,只有队列的大小等于上限(limit)或者下限(0)时,才调用notifyAll方法。如果队列的大小既不等于上限,也不等于下限,任何线程调用enqueue或者dequeue方法时,都不会阻塞,都能够正常的往队列中添加或者移除元素。
wait()/notify()方法
生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。
java中多线程的实现方法有两种:1.直接继承thread类;2.实现runnable接口;同步的实现方法有五种:1.同步方法;2.同步代码块;3.使用特殊域变量(volatile)实现线程同步;4.使用重入锁实现线程同步;5.使用局部变量实现线程同步
。
其中多线程实现过程中需注意重写或者覆盖run()方法,而对于同步的实现方法中使用较常使用的是利用synchronized编写同步方法和代码块。
你的synchronized将while循环都锁住了,所以其中一个线程会将整个while循环执行玩再走其他线程,但你的共享数据这时候已经被循环至0了,所以只有一个线程在执行
线程同步主要有以下种方法(示例中是实现计数的功能):
1、同步方法,即使用synchronized关键字修饰方法,例如:
public synchronized void add(int c){...}
2、同步代码块,即有synchronized关键字修饰的语句块,例如:
public void addAndGet(int c){
synchronized(this){
count += c;
}
}
3、使用特殊域变量(volatile)实现线程同步,该方法不能保证绝对的同步。
例如:private volatile int count = 0;
4、使用锁实现线程同步,例如:
private Lock lock = new ReentrantLock();
public void add(int c) {
lock.lock();//上锁
try{
count += c;
}finally{
lock.unlock();//解锁
}
}
5、使用原子变量实现线程同步,在java的util.concurrent.atomic包中提供了创建了原子类型变量的工具类,例如:
private AtomicInteger count= new AtomicInteger(1);
public void add(int c) {
count.addAndGet(c);
}
6、使用局部变量实现线程同步,如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本, 副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。
ThreadLocal 类的常用方法
new ThreadLocalT() : 创建一个线程本地变量
get() : 返回此线程局部变量的当前线程副本中的值
initialValue() : 返回此线程局部变量的当前线程的"初始值"
set(T value) : 将此线程局部变量的当前线程副本中的值设置为value
示例代码:
private static ThreadLocalInteger count= new ThreadLocalInteger(){
@Override
protected Integer initialValue(){
return 1;
}
};
public void add(int c){
count.set(count.get() + c);
}
7、使用阻塞队列实现,例如LinkedBlockingQueue,具体使用可百度LinkedBlockingQueue的用法或查看java文档。