java线程多线程join编程 现实生活中,有些工作是需要团队中成员依次完成的,这就涉及到了一个顺序问题。现在有T1、T2、T3三个工人,如何保证T2在T1执行完后执行,T3在T2执行完后执行?
问题分析:首先问题中有三个实体,T1、T2、T3, 因为是多线程编程,所以都要设计成线程类。关键是怎么保证线程能依次执行完呢?
Java实现过程如下: Java代码 收藏代码 public class T1 implements Runnable{
@Override
public void run() {
try {
System.out.println("T1开始工作.....");
Thread.sleep(RandomUtils.nextInt(300));
System.out.println("T1结束工作>>>>>");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Java代码 收藏代码 package thread.join.demo1;
import org.apache.commons.lang.math.RandomUtils;
public class T2 implements Runnable{
@Override
public void run() {
try{
System.out.println("T2开始工作.....");
Thread.sleep(RandomUtils.nextInt(300));
System.out.println("T2结束工作>>>>>");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Java代码 收藏代码 public class T3 implements Runnable{
@Override
public void run() {
try{
System.out.println("T3开始工作.....");
Thread.sleep(RandomUtils.nextInt(300));
System.out.println("T3结束工作>>>>>");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Java代码 收藏代码 public class Main {
public static void main(String[] args){
Thread t1 = new Thread(new T1());
Thread t2 = new Thread(new T2());
Thread t3 = new Thread(new T3());
t1.start();
t2.start();
t3.start();
System.out.println("T1、T2、T3依次工作结束.");
}
}
运行结果: T1开始工作….. T2开始工作….. T3开始工作….. T1、T2、T3依次工作结束. T3结束工作»»> T2结束工作»»> T1结束工作»»>
说明:从结果来看,T1、T2、T3并没有依次执行。查看JDK文档,java.lang.Thread 类有三个join()方法,其解释为:等待该线程终止。试用它来解决该问题……
Main.java修改如下: Java代码 收藏代码 public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new T1());
Thread t2 = new Thread(new T2());
Thread t3 = new Thread(new T3());
t1.start();
t1.join();
t2.start();
t2.join();
t3.start();
t3.join();
System.out.println("T1、T2、T3依次工作结束.");
}
}
运行结果: T1开始工作….. T1结束工作»»> T2开始工作….. T2结束工作»»> T3开始工作….. T3结束工作»»> T1、T2、T3依次工作结束.
查看jdk源码,其中join方法代码片断如下:
Java代码 收藏代码
/**
* Waits at most millis
milliseconds for this thread to
* die. A timeout of 0
means to wait forever.
*
* @param millis the time to wait in milliseconds.
* @exception InterruptedException if any thread has interrupted
* the current thread. The interrupted status of the
* current thread is cleared when this exception is thrown.
*/
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
单纯从代码上看:如果线程被生成了,但还未被起动,isAlive()将返回false,调用它的join()方法是没有作用的,将直接继续向下执行。在Main.java类中,t1.join()是判断t1线程的状态,如果t1的isActive()方法返回false,在 t1.join(),这一点就不用阻塞了,可以继续向下进行了。从源码里看,wait方法中有参数,也就是不用唤醒谁,只是不再执行wait,向下继续执行而已。在join()方法中,对于isAlive()和wait()方法的作用对象是个比较让人困惑的问题: isAlive()方法的签名是:public final native boolean isAlive(),也就是说isAlive()是判断当前线程的状态,也就是t1的状态。
Eclipse + CDT:
pthread_create函数编译时报错:undefined reference to pthread_create’
undefined reference to
pthread_create’
由于pthread 库不是 Linux 系统默认的库,连接时需要使用静态库 libpthread.a,所以在使用pthread_create()创建线程,以及调用 pthread_atfork()函数建立fork处理程序时,在编译中要加 -lpthread参数。 例如:在加了头文件#include 之后执行 pthread.c文件,需要使用如下命令:
gcc thread.c -o thread -lpthread
问题原因:
pthread 库不是 Linux 系统默认的库,连接时需要使用静态库 libpthread.a,所以在使用pthread_create()创建线程,以及调用 pthread_atfork()函数建立fork处理程序时,需要链接该库。 问题解决: 在编译中要加 -lpthread参数 gcc thread.c -o thread -lpthread thread.c为你些的源文件,不要忘了加上头文件#include
解决方法为:
Project->Properties->C/C++ Build->Settings->GCC C++ Linker->Libraries 在Libraries(-l)中添加pthread即可 在Libraries search path(-L)中添加crypto即可
pthread_t在头文件/usr/include/bits/pthreadtypes.h中定义: typedef unsigned long int pthread_t; 它是一个线程的标识符。
函数pthread_create用来创建一个线程,它的原型为:
extern int pthread_create __P ((pthread_t *__thread, __const pthread_attr_t *__attr,
void *(*__start_routine) (void *), void *__arg));
第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数。这里,我们的函数thread不需要参数,所以最后一个参数设为空指针。第二个参数我们也设为空指针,这样将生成默认属性的线程。对线程属性的设定和修改我们将在下一节阐述。当创建线程成功时,函数返回0,若不为0则说明创建线程失败,常见的错误返回代码为EAGAIN和EINVAL。前者表示系统限制创建新的线程,例如线程数目过多了;后者表示第二个参数代表的线程属性值非法。创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,原来的线程则继续运行下一行代码。
函数pthread_join用来等待一个线程的结束。函数原型为:
extern int pthread_join __P ((pthread_t __th, void **__thread_return)); 第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。一个线程的结束有两种途径,一种是象我们上面的例子一样,函数结束了,调用它的线程也就结束了;另一种方式是通过函数pthread_exit来实现。它的函数原型为:
extern void pthread_exit __P ((void *__retval)) __attribute__ ((__noreturn__));
唯一的参数是函数的返回代码,只要pthread_join中的第二个参数thread_return不是NULL,这个值将被传递给 thread_return。最后要说明的是,一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返回,其余调用pthread_join的线程则返回错误代码ESRCH。在这一节里,我们编写了一个最简单的线程,并掌握了最常用的三个函数pthread_create,pthread_join和pthread_exit。下面,我们来了解线程的一些常用属性以及如何设置这些属性。
互斥锁用来保证一段时间内只有一个线程在执行一段代码。
函数pthread_mutex_init用来生成一个互斥锁。NULL参数表明使用默认属性。如果需要声明特定属性的互斥锁,须调用函数 pthread_mutexattr_init。函数pthread_mutexattr_setpshared和函数 pthread_mutexattr_settype用来设置互斥锁属性。前一个函数设置属性pshared,它有两个取值, PTHREAD_PROCESS_PRIVATE和PTHREAD_PROCESS_SHARED。前者用来不同进程中的线程同步,后者用于同步本进程的不同线程。在上面的例子中,我们使用的是默认属性PTHREAD_PROCESS_ PRIVATE。后者用来设置互斥锁类型,可选的类型有PTHREAD_MUTEX_NORMAL、PTHREAD_MUTEX_ERRORCHECK、 PTHREAD_MUTEX_RECURSIVE和PTHREAD _MUTEX_DEFAULT。它们分别定义了不同的上所、解锁机制,一般情况下,选用最后一个默认属性。
pthread_mutex_lock声明开始用互斥锁上锁,此后的代码直至调用pthread_mutex_unlock为止,均被上锁,即同一时间只能被一个线程调用执行。当一个线程执行到pthread_mutex_lock处时,如果该锁此时被另一个线程使用,那此线程被阻塞,即程序将等待到另一个线程释放此互斥锁。
http://zhuwenlong.blog.51cto.com/209020/40339