多线程

来源:互联网 发布:java io 断开的管道 编辑:程序博客网 时间:2024/06/08 14:38

  Java语言基础:多线程 收藏 此文于2011-04-02被推荐到CSDN首页
如何被推荐?
1.  有两种方法可以创建并运行一个线程:

继承Thread类并覆盖Run方法,Run中的代码就在另一个线程执行。
view plaincopy to clipboardprint?
class MyThread extends Thread {  
    MyThread() {  
        // 调用下面代码,线程开始运行  
        start();  
    }  
   
    @Override 
    public void run() {  
        // 这里的代码是在线程中执行的  
        int i = 0;  
        while (i < 20)  
        {  
            System.out.println(i);  
            try {  
                sleep(100);  
            } catch (InterruptedException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
            ++i;  
        }  
    }  
}  
   
public class Main {              
    public static void main(String[] args) {  
        MyThread myThread = new MyThread();  
    }  

class MyThread extends Thread {
    MyThread() {
        // 调用下面代码,线程开始运行
        start();
    }
 
    @Override
    public void run() {
        // 这里的代码是在线程中执行的
        int i = 0;
        while (i < 20)
        {
            System.out.println(i);
            try {
                sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            ++i;
        }
    }
}
 
public class Main {           
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
    }
}
 

实现Runnable接口并传给新建的Thread类,实现类的Run方法即在另一个线程执行。
view plaincopy to clipboardprint?
// 实现Runnable接口  
public class Main implements Runnable {              
    @Override 
    public void run() {  
        // 这里的代码是在线程中执行的  
        int i = 0;  
        while (i < 20)  
        {  
            System.out.println(i);  
            try {  
                Thread.sleep(100);  
            } catch (InterruptedException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
            ++i;  
        }  
    }  
   
    public static void main(String[] args) {  
        Main runable = new Main();  
        new Thread(runable).start();  
    }  

// 实现Runnable接口
public class Main implements Runnable {           
    @Override
    public void run() {
        // 这里的代码是在线程中执行的
        int i = 0;
        while (i < 20)
        {
            System.out.println(i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            ++i;
        }
    }
 
    public static void main(String[] args) {
        Main runable = new Main();
        new Thread(runable).start();
    }
}
 

2.  后台线程(daemon)不属于程序不可或缺的一部分,当程序存在非后台线程时,程序就不会终止;而如果非后台线程都结束了,此时不管有没有后台线程,程序都可以随时终止。要设定一个线程为后台线程,可以调用Thread.setDaemon(true),在一个后台线程中创建其他线程,这些线程也自动被设为后台线程:
view plaincopy to clipboardprint?
class MyThread extends Thread {  
    MyThread() {  
        // 把该线程设为后台线程  
        setDaemon(true);  
        // 调用下面代码,线程开始运行  
        start();  
    }  
   
    @Override 
    public void run() {  
        // 这里的代码是在线程中执行的  
        int i = 0;  
        while (i < 20)  
        {  
            System.out.println(i);  
            try {  
                sleep(100);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
            ++i;  
        }  
    }  
}  
 
public class Main{  
    public static void main(String[] args) {  
        MyThread mythread = new MyThread();  
        // mythread.run还没有执行完就结束程序了  
    }  
}  
// 程序只打印了0就结束了,而前面的例子程序会打印到19为止 
class MyThread extends Thread {
    MyThread() {
        // 把该线程设为后台线程
        setDaemon(true);
        // 调用下面代码,线程开始运行
        start();
    }
 
    @Override
    public void run() {
        // 这里的代码是在线程中执行的
        int i = 0;
        while (i < 20)
        {
            System.out.println(i);
            try {
                sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ++i;
        }
    }
}

public class Main{
    public static void main(String[] args) {
        MyThread mythread = new MyThread();
        // mythread.run还没有执行完就结束程序了
    }
}
// 程序只打印了0就结束了,而前面的例子程序会打印到19为止
 
3.  在上面的例子中,如何让主线程等到后台线程结束时才结束呢?答案是调用后台线程的jion()方法,可以传入一个超时参数,如果不传则表示一直等到后台线程结束才返回:
view plaincopy to clipboardprint?
class MyThread extends Thread {  
    MyThread() {  
        // 把该线程设为后台线程  
        setDaemon(true);  
        // 调用下面代码,线程开始运行  
        start();  
    }  
   
    @Override 
    public void run() {  
        // 这里的代码是在线程中执行的  
        int i = 0;  
        while (i < 20)  
        {  
            System.out.println(i);  
            try {  
                sleep(100);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
            ++i;  
        }  
    }  
}  
   
public class Main{  
    public static void main(String[] args) {  
        MyThread mythread = new MyThread();  
        try {  
            // 等待后台线程结束  
            mythread.join();  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
    }  

class MyThread extends Thread {
    MyThread() {
        // 把该线程设为后台线程
        setDaemon(true);
        // 调用下面代码,线程开始运行
        start();
    }
 
    @Override
    public void run() {
        // 这里的代码是在线程中执行的
        int i = 0;
        while (i < 20)
        {
            System.out.println(i);
            try {
                sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ++i;
        }
    }
}
 
public class Main{
    public static void main(String[] args) {
        MyThread mythread = new MyThread();
        try {
            // 等待后台线程结束
            mythread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
4. 当两个线程同时读写同一份数据时,可能会引起资源冲突,这时就需要在并行机制之外,再提供一种同步机制,使对数据的读写可以有序的进行,Java对此的处理非常简单,就是使用synchronized关键字:
在普通方法前面加上synchronized,使得这个方法变成同步方法,先看下面例子,当主线程和工作线程同时调用synProc时,谁先调用到,谁就获得一个锁,另外一个只能等待,这样就保持在多线程环境下调用这个方法是有序的:
view plaincopy to clipboardprint?
class MyThread extends Thread {  
    MyThread() {  
        start();  
    }  
   
    @Override 
    public void run() {  
        synProc();  
    }  
   
    synchronized public void synProc(){  
        int count = 0;  
        while (count++ < 10) {  
            try {  
                sleep(100);  
                System.out.println("synProc: " + count);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
}  
   
public class Main{  
    public static void main(String[] args) {  
        MyThread thread = new MyThread();  
        thread.synProc();  
    }  
}  
// 输出结果是:  
synProc: 1 
synProc: 2 
synProc: 3 
synProc: 4 
synProc: 5 
synProc: 6 
synProc: 7 
synProc: 8 
synProc: 9 
synProc: 10 
synProc: 1 
synProc: 2 
synProc: 3 
synProc: 4 
synProc: 5 
synProc: 6 
synProc: 7 
synProc: 8 
synProc: 9 
synProc: 10 
class MyThread extends Thread {
    MyThread() {
        start();
    }
 
    @Override
    public void run() {
        synProc();
    }
 
    synchronized public void synProc(){
        int count = 0;
        while (count++ < 10) {
            try {
                sleep(100);
                System.out.println("synProc: " + count);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
 
public class Main{
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.synProc();
    }
}
// 输出结果是:
synProc: 1
synProc: 2
synProc: 3
synProc: 4
synProc: 5
synProc: 6
synProc: 7
synProc: 8
synProc: 9
synProc: 10
synProc: 1
synProc: 2
synProc: 3
synProc: 4
synProc: 5
synProc: 6
synProc: 7
synProc: 8
synProc: 9
synProc: 10
 

其实synchronized方法是在对象级别上的,每个对象都有一个锁,当调用它的任意一个同步方法时,就是去获得这个对象锁,当获得对象锁时,其他同步方法也不能同时被调用了,只能等这个方法执行完才可以被调用,下面代码清楚地说明这一点:
view plaincopy to clipboardprint?
class MyThread extends Thread {  
    MyThread() {  
        start();  
    }  
   
    @Override 
    public void run() {  
        synProc();  
    }  
   
    synchronized public void synProc(){  
        int count = 0;  
        while (count++ < 10) {  
            try {  
                sleep(100);  
                System.out.println("synProc: " + count);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
   
    synchronized public void synProc2() {  
        int count = 0;  
        while (count++ < 10) {  
            try {  
                sleep(100);  
                System.out.println("synProc2: " + count);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
}  
   
public class Main{  
    public static void main(String[] args) {  
        MyThread thread = new MyThread();  
        thread.synProc2();  
    }  
}  
// 输出  
synProc2: 1 
synProc2: 2 
synProc2: 3 
synProc2: 4 
synProc2: 5 
synProc2: 6 
synProc2: 7 
synProc2: 8 
synProc2: 9 
synProc2: 10 
synProc: 1 
synProc: 2 
synProc: 3 
synProc: 4 
synProc: 5 
synProc: 6 
synProc: 7 
synProc: 8 
synProc: 9 
synProc: 10 
class MyThread extends Thread {
    MyThread() {
        start();
    }
 
    @Override
    public void run() {
        synProc();
    }
 
    synchronized public void synProc(){
        int count = 0;
        while (count++ < 10) {
            try {
                sleep(100);
                System.out.println("synProc: " + count);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
 
    synchronized public void synProc2() {
        int count = 0;
        while (count++ < 10) {
            try {
                sleep(100);
                System.out.println("synProc2: " + count);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
 
public class Main{
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.synProc2();
    }
}
// 输出
synProc2: 1
synProc2: 2
synProc2: 3
synProc2: 4
synProc2: 5
synProc2: 6
synProc2: 7
synProc2: 8
synProc2: 9
synProc2: 10
synProc: 1
synProc: 2
synProc: 3
synProc: 4
synProc: 5
synProc: 6
synProc: 7
synProc: 8
synProc: 9
synProc: 10

synchronized可以加到静态方法前面,每个类也有一个锁,调用同步静态方法就是获得类级别的锁,这使类中的所有同步静态方法变得有序,即只有一个同步静态方法被调用,其他的同步静态就只好等待它结束才能被调用。
synchronized还可以加在方法之内,称为同步块,如synchronized(obj){...}这样的语法,这里其实是获得obj对象的锁,因此Obj的同步方法也会受它影响,即对于Obj的同步块被执行时,Obj的同步方法必须等同步块执行完才能被调用:
view plaincopy to clipboardprint?
class MyThread extends Thread {  
    MyThread() {  
        start();  
    }  
   
    @Override 
    public void run() {  
        synProc();  
    }  
   
    public void synProc(){  
        int count = 0;          
        synchronized (this) {  
            do {  
                try {  
                    sleep(50);  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
                System.out.println("synProc :" + count);  
            } while (count++ < 3);          
        }  
    }  
   
    synchronized public void synProc2() {  
        int count = 0;  
        do {  
            try {  
                sleep(50);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
            System.out.println("synProc2 :" + count);  
        } while (count++ < 3);  
    }  
}  
   
public class Main{  
    public static void main(String[] args) {  
        MyThread thread = new MyThread();  
        thread.synProc2();  
    }  
}  
// 输出:  
synProc2 :0 
synProc2 :1 
synProc2 :2 
synProc2 :3 
synProc :0 
synProc :1 
synProc :2 
synProc :3 
class MyThread extends Thread {
    MyThread() {
        start();
    }
 
    @Override
    public void run() {
        synProc();
    }
 
    public void synProc(){
        int count = 0;       
        synchronized (this) {
            do {
                try {
                    sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("synProc :" + count);
            } while (count++ < 3);       
        }
    }
 
    synchronized public void synProc2() {
        int count = 0;
        do {
            try {
                sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("synProc2 :" + count);
        } while (count++ < 3);
    }
}
 
public class Main{
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.synProc2();
    }
}
// 输出:
synProc2 :0
synProc2 :1
synProc2 :2
synProc2 :3
synProc :0
synProc :1
synProc :2
synProc :3

5.  线程之间的等待与通知通过wait和notify,notifyAll来实现。

这三个方法都必须在对象的同步块中执行,否则运行期会出现IllegalMonitorStateException异常。
当线程A调用Obj.wait()时,A将被挂起,直到另一个线程B调用Obj.notify()或Obj.notifyAll(),A才被重新唤醒。
如果只有一个线程调用Obj.wait(),另一个线程只需要调用Obj.notify()即可;但如果有多个线程调用Obj.wait(),则另一个线程必须调用Obj.notifyAll()才可以将所有的线程唤醒。
下面代码演示了一个writer和多个reader的协作过程:

view plaincopy to clipboardprint?
class Writer extends Thread {      
    private char chr;  
   
    @Override 
    public void run() {          
        for (char c = 'A'; c <= 'Z'; ++c){  
            chr = c;  
            // 通知Reader可以读了  
            synchronized (this) {  
                notifyAll();  
            }  
            // 过会儿再写  
            try {  
                sleep(100);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
   
    public char getChar() {  
        return chr;  
    }  
}  
   
class Reader extends Thread {  
    private Writer writer;  
   
    Reader(Writer writer) {  
        this.writer = writer;  
        start();  
    }  
   
    @Override 
    public void run() {  
        while (true){  
            // 等待Writer写  
            synchronized (writer) {  
                try {  
                    // 此处Reader线程将被挂起  
                    writer.wait();  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
            }  
            // 读取Writer写的内容  
            char chr = writer.getChar();  
            System.out.print(chr + " ");  
            // 读到Z即结束  
            if (chr == 'Z') {  
                System.out.println();  
                break;  
            }  
        }  
    }  
}  
   
public class Main{  
    public static void main(String[] args) {  
        Writer writer = new Writer();  
        Reader reader1 = new Reader(writer);  
        Reader reader2 = new Reader(writer);  
        // 开始  
        writer.start();  
    }  
}  
// 最后的输出是:  
A A B B C C D D E E F F G G H H I I J J K K L L M M N N O O P P Q Q R R S S T T U U V V W W X X Y Y Z   

class Writer extends Thread {   
    private char chr;
 
    @Override
    public void run() {       
        for (char c = 'A'; c <= 'Z'; ++c){
            chr = c;
            // 通知Reader可以读了
            synchronized (this) {
                notifyAll();
            }
            // 过会儿再写
            try {
                sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
 
    public char getChar() {
        return chr;
    }
}
 
class Reader extends Thread {
    private Writer writer;
 
    Reader(Writer writer) {
        this.writer = writer;
        start();
    }
 
    @Override
    public void run() {
        while (true){
            // 等待Writer写
            synchronized (writer) {
                try {
                    // 此处Reader线程将被挂起
                    writer.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // 读取Writer写的内容
            char chr = writer.getChar();
            System.out.print(chr + " ");
            // 读到Z即结束
            if (chr == 'Z') {
                System.out.println();
                break;
            }
        }
    }
}
 
public class Main{
    public static void main(String[] args) {
        Writer writer = new Writer();
        Reader reader1 = new Reader(writer);
        Reader reader2 = new Reader(writer);
        // 开始
        writer.start();
    }
}
// 最后的输出是:
A A B B C C D D E E F F G G H H I I J J K K L L M M N N O O P P Q Q R R S S T T U U V V W W X X Y Y Z
Z

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/linzhengqun/archive/2011/04/02/6296458.aspx

原创粉丝点击