标签归档:线程

Java线程同步之CountDownLatch

1、类说明

jdk的concurrent包中的CountDownLatch类是一个线程同步的辅助类,它使得线程可以一直等待在其它线程中执行的操作,直到此操作结束。CountDownLatch在初始化的时候指定一个大小值N,调用CountDownLatch的await方法的线程会陷入等待之中,直到这个CountDownLatch对象的countDown方法被调用N次为止,无论是在一个线程中调用N次,还是在N个线程中被调用一次。只有这个对应的CountDownLatch对象的countDown方法总被调用次数为N次之后,这个等待的线程才能继续往下执行。

其原理也容易理解,初始化的时候指定要等待的计数的次数,每调用一次countDown就对这个计数减一,直到计数被减到0,等待的线程就可以继续运行了。

2、await

CountDownLatch的await方法会使得当前线程进入等待状态,直到最新的一次计数被减到0为止。如果当前的计数已经是0了,那么这个方法会马上返回。这个函数有个代参的重载函数,可以设置一个最长的等待时长。在等待时长内,如果计数器被减到0,这个函数会返回true,或者达到等待时长,这个函数会返回false。(被中断情况下抛异常)

3、countDown

使计数减一,初始化的计数不能重新设定,只能通过countDown来对计数减一

相关阅读:

Java Hashtable多线程操作遍历问题 http://www.linuxidc.com/Linux/2013-01/78574.htm

Java多线程顺序执行 http://www.linuxidc.com/Linux/2012-07/65033.htm

Java多线程问题之同步器CyclicBarrier http://www.linuxidc.com/Linux/2012-07/64593.htm

Java多线程之wait()和notify() http://www.linuxidc.com/Linux/2012-03/57067.htm

Java多线程之synchronized http://www.linuxid

Android 处理多线程 UserTask

Android 处理多线程时,不能在线程范围内调用UI,通过这个方式能够很好的在线程中,对UI进行控制。

UserTask下载

 /*多线程处理-程序加载线程*/ 
 private class LoginFromTask extends UserTask
 { 
 /**  
 * 线程启动初始化操作  
 */ 
 @Override 
 public void onPreExecute()
 {
 //在这儿进行线程运行前的初始化,比如显示一个提示框或进度条 
 }   
 /**    
 * 需要长时间阻塞处理的任务    
 */   
 @Override 
 public String doInBackground(String…stgs)
 {     线程中的处理,这儿不能操作UI

return null;
//   publishProgress();//调用这个函数好后会激活onProgressUpdate()事件 

/**  
* 线程内更新处理  
*/  
 @Override
 public void onProgressUpdate(Integer… progress)     {

//这边用于处理线程未完成的提示处理,例如进度条更新

}   
/**    
* 阻塞任务执行完后的清理工作    
*/   
@Overrid

Linux平台用C++封装线程读写锁

在Linux平台上已经有现成的线程读写锁pthread_rwlock_t以及相关API,现将这些API封装成与Win32平台上相同的接口,以便于编写跨平台程序。这些API包括pthread_rwlock_init,pthread_rwlock_rdlock,pthread_rwlock_tryrdlock,pthread_rwlock_wrlock,pthread_rwlock_trywrlock,pthread_rwlock_unlock,pthread_rwlock_destroy,可在Linux在线手册上查阅它们的说明。下边的代码在VS2005中编辑,在Fedora 13虚拟机中编译,测试通过。

RWLockImpl.h

#ifndef _RWLockImpl_Header
#define _RWLockImpl_Header

#include
#include #include
#include

using namespace std;

/*
 读写锁允许当前的多个读用户访问保护资源,但只允许一个写读者访问保护资源
*/

//—————————————————————–
class CRWLockImpl
{
protected:
 CRWLockImpl();
 ~CRWLockImpl();
 void ReadLockImpl();
 bool TryReadLockImpl();
 void WriteLockImpl();
 bool TryWriteLockImpl();
 void UnlockImpl();

private:
 pthread_rwlock_t m_rwl;
};

//—————————————————————–

class CMyRWLock: private CRWLockImpl
{
public:

 //创建读/写锁
 CMyRWLock(){};

 //销毁读/写锁
 ~CMyRWLock(){};

 //获取读锁
 //如果其它一个线程占有写锁,则当前线程必须等待写锁被释放,才能对保护资源进行访问
 void ReadLock();

 //尝试获取一个读锁
 //如果获取成功,则立即返回true,否则当另一个线程占有写锁,则返回false
 bool TryReadLock();

 //获取写锁
 //如果一个或更多线程占有读锁,则必须等待所有锁被释放
 //如果相同的一个线程已经占有一个读锁或写锁,则返回结果不确定
 void WriteLock();

 //尝试获取一个写锁
 //如果获取成功,则立即返回true,否则当一个或更多其它线程占有读锁,返回false
 //如果相同的一个线程已经占有一个读锁或写锁,则返回结果不确定
 bool TryWriteLock();

 //释放一个读锁或写锁
 void Unlock();

private:
 CMyRWLock(const CMyRWLock&);
 CMyRWLock& operator = (const CMyRWLock&);
};

inline void CMyRWLock::ReadLock()
{
 ReadLockImpl();
}

inline bool CMyRWLock::TryReadLock()
{
 return TryReadLockImpl();
}

inline void CMyRWLock::WriteLock()
{
 WriteLockImpl();
}

inli

Java语言规范线程形式范例

  在一开始接触Java的时候我们没有很注意Java语言规范,其实这是不对的。下面我们就来看看开始执行Java语言规范程序后,至少会有一个线程开始操作,有操作的是被称为主线程的线程,主线程执行输入类的main()。当main()里的所有处理均结束后,则主线程也同时结束。

  当应用程序的规模大到一定程度,程序里的多线程会以每种形式存在。以下是几个常见的范例:

  1) GUI应用程序。

  2) 比较花费时间的I/O处理。

  3) 多个客户端。

  如欲启动线程时,有下列两种方法:

  1) 利用Thread类的子类的实例,启动线程。

  2) 利用Runnable接口的实现类的实例,启动线程。

  要注意的是,“Thread的实例”和“线程本身”是两个不同的部分。即使建立了Thread的实例,也还没有启动线程,而且就算线程已经结束,Thread实例也不会就这样消失。

  建立一个实现Runnable接口的类,将该类的实例传给Thread的构造函数,调用start()…,这就是利用Runnable接口来启动线程的方法。

  记住:无论哪种方式,启动新线程的方法永远是Thread类的start()。

  利用Thread类的sleep()可以暂停线程的执行。执行下面的语句时,即可让当前的线程(执行此语句的线程)暂时停止越1000ms。

  Thread.sleep(1000);

  当实例方法加上关键字synchronized声明之后,就可以只让一个线程操作某类实例的这类方法。“让一个线程操作”并不是说只能让某一个特定的线程操作而已,而是指一次只能让一个线程执行。这种方法称为synchronized方法(同步方法)。

  synchronized实例方法是使用this锁定去做线程的共享互斥。synchronized类方法是使用该类的类对象的锁定去做线程的共享互斥。

  Java语言规范线程的协调(这三种方法执行的前提是执行线程手中有obj的锁):

  1) obj.wait()是把现在的线程放到obj的wait set;

  2) obj.notify()是从obj的wait set里唤醒一个线程;

  3) obj.notifyAll()是唤醒所有在obj的wait set里的线程。

  被唤醒的线程只是处于等锁状态(但已经不再wait set中了),当时的obj的锁还掌握在执行notify()或notifyAll()的线程手上。当唤醒的线程得到锁之后,将从wait()之后继续执行。Introduction

  Java语言规范多线程程序的评量标准

  安全性--不损坏对象。

  生存性--进行必要的处理。(liveness)

  复用性--可再利用类。

  性 能--能快速、大量进行处理。

  Single Threaded Execution - 能通过这座桥的,只有一个人

  Single Threaded Execution是指“以一个线程执行”的意思。就象细独木桥只能允许一个人通过一样,这个模式用来限制只让一个线程运行。

  在Single Threaded Execution Pattern中,我们将unsafeMethod加以防卫,限制同时只能有一个线程可以调用它(加上synchronized)。这个必须让单线程执行的程序范围,我们称为“临界区”(critical section)。

  使用Single Threaded Execution Pattern时,可能会有发生死锁(deadlock)的危险。

  当SharedResource的字段开放给子类访问时,可能会因为子类写出unsafeMethod而导致丧失安全性。

  synchronized方法和synchronized块,无论碰到return或是异常,都会确实解除锁定。

  结论,Java语言规范中:

  1) 基本类型、引用类型的指定、引用是原子的操作。

  2) 但是long和double的指

Android线程使用注意问题

<

div id=”content” contentScore=”2570″>一、众所周知Hanlder是线程与Activity通信的桥梁,我们在开发好多应用中会用到线程,有些人处理不当,会导致当程序结束时,线程并没有被销毁,而是一直在后台运行着,当我们重新启动应用时,又会重新启动一个线程,周而复始,你启动应用次数越多,开启的线程数就越多,你的机器就会变得越慢。这时候就需要在destory()方法中对线程进行一下处理!

二、main。xml布局文件

 
Android=”http://schemas.android.com/apk/res/android”
    android:orientation=”vertical”
    android:layout_width=”fill_parent”
    android:layout_height=”fill_parent”
    >
            android:id=”@+id/textview01″
        android:layout_width=”fill_parent”
        android:layout_height=”wrap_content”
        android:text=”daming 原创”
     />

三、Threademo类

package com.cn.android;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.widget.TextView;

public class ThreadDemo extends Activity {
    /** Called when the activity is first created. */
    
    private static final String TAG = “ThreadDemo”;
    private int count = 0;
    private Handler mHandler = new Handler();
    private TextView mTextView = null;
    
    private Runnable mRunnable = new Runnable(){

        @Override
        public void run() {
            // TODO Auto-generated method stub
            Log.e(TAG,Thread.currentThread().getName()+” “+count);
            count++;
            mTextView.setText(“”+count);

         //每两秒重启一下线程
            mHandler.postDelayed(mRunnable, 2000);
        }
    };
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mTextView = (TextView)findViewById(R.id.textview01);

      //通过handler启动线程
        mHandler.post(mRunnable);
    }
    
    @Override
    protected void onDestroy() {
        mHandler.removeCallbacks(mRunnable);
        super.onDestroy();
    }
}

四、特别注意onDestroy()方法中的代码

//将线程销毁,否则返回activity,但是线程会一直在执行,log里面的信息会增加,会消耗过多的内存\/div>

Java并发编程–多线程之HelloWorld

上篇文章我们介绍了一些基本概念,进程、线程、并发(http://www.linuxidc.com/Linux/2015-05/118017.htm)。下面我们开始写第一个多线程的程序。

两种方式:一、实现Runnable接口;二、基础Thread类。

一、实现Runnable接口

package com.tgb.klx.thread;

public class hello1 implements Runnable {

 public hello1() {

 }

 public hello1(String name) {
  this.name = name;
 }

 public void run() {
  for (int i = 0; i < 5; i++) {
   System.out.println(name + “运行    ” + i);
  }
 }

 public static void main(String[] args) {
  hello1 h1 = new hello1(“线程A”);
  Thread demo1 = new Thread(h1);
  hello1 h2 = new hello1(“线程B”);
  Thread demo2 = new Thread(h2);
  demo1.start();
  demo2.start();
 }

 private String name;

}

运行结果:

Java并发编程--多线程之HelloWorld

二、基于Thread类

package com.tgb.klx.thread;
public class hello2 extends Thread {

 public hello2() {

 }

 public hello2(String name) {
  this.name = name;
 }

 public void run() {
  for (int i = 0; i < 5; i++) {
   System.out.println(name + “运行    ” + i);
  }
 }

 public static void main(String[] args) {
  hello2 h1 = new hello2(“A”);
  hello2 h2 = new hello2(“B”);
  h1.start();
  h2.start();
 
 }

 private String name;
}

运行结果:

Java并发编程--多线程之HelloWorld

实现Runnable接口的方式,需要创建一个Thread类,将实现runnable的类的实例作为参数传进去,启动一个线程,如果直接调用runnable的run方法跟调用普通类的方法没有区别,不会创建新的线程。

Thread类实现了Runnable接口,Thread类也有run方法,调用Thread的run方法同样也不会新建线程,和调用普通方法没有区别,所以大家在使用多线程时一定要注意。

总结:

以上两种方式都可以实现,具体选择哪种方式根据情况决定。java里面不支持多继承,所以实现runnable接口的方式可能更灵活一点。

Linux下的多线程定时器实现

一、功能:

Linux下编写一个程序库,实现定时器的功能,它能为用户提供在同一进程中多次使用的定时器。

二、实现

#include
#include
#include
#include
#include
#include
#include #include
#define DEFAULT_INTERVAL 1

int TIMER_CNT = 0;
class Timer;                //定时器
class TimerManager;        //定时器管理器

class TimerManager {

    friend class Timer;    //友元类,Timer类可分享此类的方法
public:
    typedef enum {

        TIMER_MANAGER_STOP=0,
        TIMER_MANAGER_START
    }TimerManagerState;
    static TimerManager *instance();    //当前实例
    void start();                      //启动当前线程,运行process函数
    void stop();                        //终止当前线程
    void dump();                        //清理当前剩下的无用定时器
    void add_timer(Timer *vtimer);      //线程安全的增加定时器
    void remove_timer(Timer *vtimer);  //线程安全的移除定时器
protected:
    static void *process(void *);

private:
    TimerManager();
    void add_timer_unsafe(Timer *vtimer);  //线程非安全的增加定时器,本类使用
    void remove_timer_unsafe(Timer *vtimer);//线程非安全的移除定时器,本类使用

    static TimerManager *m_instance;
    static pthread_mutex_t workmutex;
    TimerManagerState m_state;
    LIST_HEAD(,Timer) list_;                //链表头
    static int mark;
};
class Timer {

    friend class TimerManager;
public:
    typedef enum {

        TIMER_IDLE = 0,
        TIMER_ALIVE,
        TIMER_TIMEOUT
    }TimerState;
    Timer(int vinterval,void (*vfunc)(void *),void *vdata);
    void start();                          //把自己添加进定时器管理器的链表里
    void stop();                            //把自己从定时器管理器的链表里移除
    void reset(int vinterval);              //重置
    ~Timer();

private:
    int id;                                //当前定时器的ID
    int m_interval;                        //定时器的定时时间,单位为秒
    int m_counter;                          //还剩下多少时间,单位为微秒
    TimerState m_state;                    //当前定时器的状态
    void (*m_func)(void *);
    void *m_data;
    LIST_ENTRY(Timer) entry_;              //当前定时器在链表中的地址
};

TimerManager *TimerManager::m_instance;
pthread_mutex_t TimerManager::workmutex;

TimerManager::TimerManager() {

    pthread_mutex_init(&workmutex,NULL);
}
TimerManager *TimerManager::instance() {

    if (m_instance == NULL) {

        pthread_mutex_lock(&workmutex);
        if (m_instance == NULL)
            m_instance = new TimerManager();
        pthread_mutex_unlock(&workmutex);
    }
    return m_instance;
}
void TimerManager::start() {

    if (m_state == TIMER_MANAGER_STOP) {

        m_state = TIMER_MANAGER_START;
        pthread_t pid;
        int res = pthread_create(&pid,NULL,process,this);
        if (res != 0) {

            printf(“pthread_create is failed\n”);
            exit(EXIT_FAILURE);
        }
    }
}
void TimerManager::stop() {

    this->m_state = TIMER_MANAGER_STOP;
}
void TimerManager::dump() {

    Timer *item;
    pthread_mutex_lock(&workmutex);
    LIST_FOREACH(item,&(this->list_),entry_) {

        if (item->m_counter == 0) {

            printf(“Timer%d will be dumped!\n”,(int)item->m_data);
            item->stop();
        }
    }
    pthread_mutex_unlock(&workmutex);
}
void *TimerManager::process(void *arg) {

    pthread_detach(pthread_self());

    TimerManager *manage = (TimerManager *)arg;
    Timer *item;
    struct timeval start,end;
    int delay;
    struct timeval tm;
    gettimeofday(&end,0);

    while (manage->m_state == TIMER_MANAGER_START) {

        tm.tv_sec = 0;
        tm.tv_usec = DEFAULT_INTERVAL * 1000;
        start.tv_sec = end.tv_sec;
        start.tv_usec = end.tv_usec;
        while (select(0,0,0,0,&tm) < 0 && errno == EINTR);
        gettimeofday(&end,0);

        delay = (end.tv_sec – start.tv_sec) * 1000;
        delay += (end.tv_usec – start.tv_usec);
        pthread_mutex_lock(&manage->workmutex);
        LIST_FOREACH(item, &(manage->list_), entry_) {

            //printf(“m_data = %d m_counter = %d “,item->m_data,item->m_counter);
            if ( item->m_counter < delay)
                item->m_counter = 0;
            else
                item->m_counter -= delay;
            //printf(“m_data = %d m_counter = %d\n”,item->m_data,item->m_counter);

            if (item->m_counter == 0) {

                if (item->m_func)
                    item->m_func(item->m_data);
                manage->remove_timer_unsafe(item);
                item->m_state = Timer::TIMER_TIMEOUT;
            }
        }
        pthread_mutex_unlock(&manage->workmutex);
    }
}
void TimerManager::add_timer(Timer* vtimer) {

    pthread_mutex_lock(&workmutex);
    LIST_INSERT_HEAD(&(this->list_),vtimer,entry_);
    pthread_mutex_unlock(&workmutex);
}
void TimerManager::remove_timer(Timer* vtimer) {

    pthread_mutex_lock(&workmutex);
    LIST_REMOVE(vtimer, entry_);
    pthread_mutex_unlock(&workmutex);
}
void TimerManager::add_timer_unsafe(Timer* vtimer) {

    LIST_INSERT_HEAD(&(this->list_),vtimer,entry_);
}
void TimerManager::remove_timer_unsafe(Timer* vtimer) {

    LIST_REMOVE(vtimer, entry_);
}

还有一个类的代码先不上传,这是我们正在学的Linux一个实验,上传的话万人都交这个代码给老师了。

三、总结:

1、按照之前我写代码的习惯,都是先声明一个类A,,接着依次实现A的方法,然后再声明一个类B,接着依次实现B的方法。

按照这个习惯,如果类A在类B的前面声明,如果类A要调用类B中的方法,就必须在定义之前声明class A,class B,接着把类A声明为类B的友元类,还要把实现放在两个类定义的后面,才不会出错。

按照这个习惯,如果类A要调用类B的方法,类B要调用A的方法,这个要怎么办?到底哪个类放在前面?和上面的情况相似。我们一定要保证某个类在调用另一个类的对象,另一个类的方法都已经实现。否则会出现类似invalid use of incomplete type ‘struct Timer’这样的错误。

2、当类中声明了静态变量,而且未初始化。这时候要在类外单独再声明一次静态变量,这样系统会自动给这些变量分配全局内存空间。这样,后面就可以放心地对静态变量进行赋值了。不然会出现类似于undefined reference to `TimerManager::m_instance’这样的错误。

3、程序中出现了死锁,process中用lock和unlock锁起一段代码,而这段代码中又有用lock和unlock锁起一段断码,这样后一段代码无法执行切程序处于挂起等待状态。

4、我的实现是通过select不断的检查时间,可是select这个函数调用占用了一些时间导致精度误差。如果我尽量少调用select函数,那么实时性不够,如果调用次数很多,那么精确度又不够。在我的代码中折中,选取1s作为调用select的间隔。

5、当Timermanage

Java多线程Callable,Future,FutureTask

我们平时接触到的多线程Thread,Runnable,这两种方式不能返回线程执行后的结果。

Callable和Future,前者产生结果,后者拿到结果。

public class GreyStartServlet extends HttpServlet {
  @Override
  public void init() throws ServletException {
    FutureTask task = new FutureTask(new Callable() {
    @Override
    public String call() throws Exception {
    start(); // 使用另一个线程来执行该方法,会避免占用Tomcat的启动时间
    return “Collection Completed”;
    }
    });
    new Thread(task).start();
  }
  // 希望Tomcat启动结束后执行的方法
  private static void start() throws Exception {
    Thread.sleep(1000);

  }
}

Linux线程的信号量同步

信号量和互斥锁(mutex)的区别:互斥锁只允许一个线程进入临界区,而信号量允许多个线程同时进入临界区。

不多做解释,要使用信号量同步,需要包含头文件semaphore.h。

主要用到的函数:

  • int sem_init(sem_t *sem, int pshared, unsigned int value);,其中sem是要初始化的信号量,pshared表示此信号量是在进程间共享还是线程间共享,value是信号量的初始值。
  • int sem_destroy(sem_t *sem);,其中sem是要销毁的信号量。只有用sem_init初始化的信号量才能用sem_destroy销毁。
  • int sem_wait(sem_t *sem);等待信号量,如果信号量的值大于0,将信号量的值减1,立即返回。如果信号量的值为0,则线程阻塞。相当于P操作。成功返回0,失败返回-1。
  • int sem_post(sem_t *sem); 释放信号量,让信号量的值加1。相当于V操作。

下列的代码演示了如何用信号量同步,模拟一个窗口服务系统。
/* @purpose: 基于信号量的多线程同步,操作系统原理中的P,V操作
 * @author: jollywing@foxmail.com
 * @create: 2015-03-20 Fri
 * */

#include #include
#include
#include
#include

/* @Scene: 某行业营业厅同时只能服务两个顾客。
 * 有多个顾客到来,每个顾客如果发现服务窗口已满,就等待,
 * 如果有可用的服务窗口,就接受服务。 */

/* 将信号量定义为全局变量,方便多个线程共享 */
sem_t sem;

/* 每个线程要运行的例程 */
void * get_service(void *thread_id)
{
    /* 注意:立即保存thread_id的值,因为thread_id是对主线程中循环变量i的引用,它可能马上被修改 */
    int customer_id = *((int *)thread_id);

    if(sem_wait(&sem) == 0) {
        usleep(100);                /* service time: 100ms */
        printf(“customer %d receive service …\n”, customer_id);
        sem_post(&sem);
    }
}

#define CUSTOMER_NUM 10

int main(int argc, char *argv[])
{
    /* 初始化信号量,初始值为2,表示有两个顾客可以同时接收服务 */
    /* @prototype: int sem_init(sem_t *sem, int pshared, unsigned int value); */
    /* pshared: if pshared == 0, the semaphore is shared among threads of a process
    * otherwise the semaphore is shared between processes.  */
    sem_init(&sem, 0, 2);

    /* 为每个顾客定义一个线程id, pthread_t 其实是unsigned long int */
    pthread_t customers[CUSTOMER_NUM];

    int i, ret;
    /* 为每个顾客生成一个线程 */
    for(i = 0; i < CUSTOMER_NUM; i++){
        int customer_id = i;
        ret = pthread_create(&customers[i], NULL, get_service, &customer_id);
        if(ret != 0){
            perror(“pthread_create”);
            exit(1);
        }
        else {
            printf(“Customer %d arrived.\n”, i);
        }
        usleep(10);
    }

    /* 等待所有顾客的线程结束 */
    /* 注意:这地方不能再用i做循环变量,因为可能线程中正在访问i的值 */
    int j;
    for(j = 0; j < CUSTOMER_NUM; j++) {
        pthread_join(customers[j], NULL);
    }

    /* Only a  semaphore that  has been initialized  by sem_init(3)
    * should be destroyed using sem_destroy().*/
    sem_destroy(&sem);
    return 0;
}

编译:gcc main.c -lpthread。

运行结果(注意,每次运行都不相同):
Customer 0 arrived.
Customer 1 arrived.
customer 0 receive service …
Customer 2 arrived.
customer 1 receive service …
Customer 3 arrived.
customer 2 receive service …
Customer 4 arrived.
customer 3 receive service …
Customer 5 arrived.
customer 4 receive service …
Customer 6 arrived.
customer 5 receive service …
Customer 7 arrived.
customer 6 receive service …
Customer 8 arrived.
customer 7 receive service …
Customer 9 arrived.
customer 8 receive service …
customer 9 receive service …

进程线程的的作用和区别

首先来回顾一下进程和线程的概念吧。

进程(Process)是计算机中已运行程序的实体。进程为曾经是分时系统的基本运作单位。

线程(thread)是操作系统能够进行运算调度的最小单位,也是进程内的一个执行单元,程内的可调度实体。

线程的状态:

1)产生(spawn)

2)中断(block)

3)非中断(unblock)

4)退出(finish)

与进程的区别:

1)地址空间:进程内的一个执行单元;进程至少有一个线程;它们共享进程的地址空间;而进程有自己独立的地址空间;

 2)资源拥有:进程是资源分配和拥有的单