线程的定义:
每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。进程也可能是整个程序或者是部分程序的动态执行。线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行。也可以把它理解为代码运行的上下文。所以线程基本上是轻量级的进程,它负责在单个程序里执行多任务。通常由操作系统负责多个线程的调度和执行。
线程的状态:
1、 new 新建
2、 Runnable 可以运行(就绪)
3、 Running 运行(正在运行)
4、 Block 阻塞 挂起
5、 Dead 死亡
线程之间的转换关系:
如何新建并启动线程:
Thread thread = new Thread(){//Thread是线程类,new Thread()即是新建了一个线程。
@Override
public void run() {//线程当然要运行代码,重写run方法即可加入此线程的运行代码。
while(true){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("1:" + Thread.currentThread().getName());
System.out.println("2:" + this.getName());
}
}
};
thread.start();//启动线程,将线程从新建状态变为可运行状态,将等待CPU调度。
Thread thread2 = new Thread(new Runnable(){//新建线程也可以使用Runnable对象,重新Runnable对象的run方法。
@Override
public void run() {//Thread类的run方法会调用传递的Runnable对象的run方法,所以这里重写Runable对象的run方法。
while(true){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("1:" + Thread.currentThread().getName());
}
}
});
thread2.start();
这两种方式没有什么区别,看个人爱好使用。
推荐第二种方法,因为这更加面向对象,它将线程要运行的代码进行了封装。
如何实现线程的互斥:
线程互斥是指对于共享的资源,在各线程访问时的排它性。当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。
java中的线程互斥使用synchronized关键字,synchronized可以声明一个代码块,可以声明一个方法(可以是静态方法)。
例:
static class Outputer{
public void output(String name){
int len = name.length();
synchronized (Outputer.class) //声明代码块,使用Outputer.class作为锁。
{
for(int i=0;i<len;i++){
System.out.print(name.charAt(i));
}
System.out.println();
}
}
public synchronized void output2(String name){ //声明方法,将使用this作为锁。
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){//声明静态方法,将使用Outputer.class作为锁。
int len = name.length();
for(int i=0;i<len;i++){
System.out.print(name.charAt(i));
}
System.out.println();
}
}
经验:设计线程互斥代码,需要考虑互斥锁和线程之间的共享数据,设计代码时尽量保证互斥锁、共享数据、synchronized声明归在同一个类的身上,这样既便于维护,同时保证了良好的高内聚,外部调用者不必关心同步控制的问题。
线程协同的通信:
线程互斥本身可以理解为线程通信的一种方式,是一个线程A说“我进去了,等我出来后你们再进”。其它线程就在外面等待,直到看见A出来,其它线程才会进去并且说“我也进去了,等我出来后你们再进”。
但是有这样一种场景,一个线程A在不停的生产面包,放进面包箱里,另一个线程B在不停的从面包箱里取出面包,然后吃掉。当面包箱满的时候,线程A应该暂停,当B吃掉面包时,面包箱变得不满,应该通知线程A继续生产,这就需要线程之间的协同通信。
java的Object对象提供了两个方法用于实现线程协同通信,wait();和notify();。
wait():在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待,并释放当前互斥锁。
notify() :唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个
wait
方法,在对象的监视器上等待。
以下是一段参考代码,实现了两个线程的交替运行:
import java.util.concurrent.atomic.AtomicInteger;
public class TraditionalThreadCommunication {
/**
* @param args
*/
public static void main(String[] args) {
final Business business = new Business();
new Thread(
new Runnable() {
@Override
public void run() {
for(int i=1;i<=50;i++){
business.sub(i);
}
}
}
).start();
for(int i=1;i<=50;i++){
business.main(i);
}
}
}
class Business {
private boolean bShouldSub = true;//是否可以由sub运行。
public synchronized void sub(int i){
while(!bShouldSub){
try {
this.wait();//不该sub方法运行时,让sub进入等待。
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for(int j=1;j<=10;j++){
System.out.println("sub thread sequence of " + j + ",loop of " + i);
}
bShouldSub = false;
this.notify();//sub方法运行完毕后,通知main运行。
}
public synchronized void main(int i){
while(bShouldSub){
try {
this.wait();//不该main运行时,让main进入等待。
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for(int j=1;j<=100;j++){
System.out.println("main thread sequence of " + j + ",loop of " + i);
}
bShouldSub = true;
this.notify();//main方法运行完毕后,通知sub运行。
}
}