Java Thread多线程

标签: java thread 多线程 | 发表时间:2012-02-09 17:43 | 作者:m13666368773
出处:http://blog.csdn.net

Java Thread多线程

Java 多线程例子1 小例子

public class ThreadDemo {   

    public static void main(String[] args) {   

        new TestThread().start();   

        while(true) {   

            System.out.println("main(): "+Thread.currentThread().getName() + " is running");   

        }   

    }   

}   

  

class TestThread extends Thread {   

public TestThread(){

super("zhuyong");//设置线程的名字,默认为“TestThread”

}

    public void run() {   

        while(true) {   

            System.out.println("TestThread: "+Thread.currentThread().getName() + " is running");   

        }   

    }   

输出结果为 写道

main(): main is running 
TestThread: Thread-0 is running 
main(): main is running 
TestThread: Thread-0 is running 
main(): main is running 
TestThread: Thread-0 is running 

Java 多线程例子2 前台线程(用户线程) 后台线程(守护线程 )

1,setDaemon(true)后就是后台线程(守护线程 ),反之就是前台线程(用户线程)

2,后台线程 和 前台线程的区别:在java程序中如果所有的前台线程都已经退出,所有的后台线程自动退出。

public class ThreadDemo {   

    public static void main(String[] args) {   

        Thread t = new TestThread();   

        t.setDaemon(true);   

        t.start();      

    }   

}   

  

class TestThread extends Thread {   

    public void run() {   

        while(true) {   

            System.out.println("TestThread: "+Thread.currentThread().getName() + " is running");   

        }   

    }   

}

 运行当前台线程main退出后自动退出。去掉setDeamon,TestThread 就不会退出

Java 多线程例子3 联合线程 join()

a,直接联合:

public class ThreadDemo {   

    public static void main(String[] args) {   

        Thread t = new TestThread();   

//      t.setDaemon(true);   

        t.start();   

        try {   

            t.join();   

        } catch (InterruptedException e) {   

            e.printStackTrace();   

        }   

        while(true) {   

            System.out.println("main(): "+Thread.currentThread().getName() + " is running");   

        }   

    }   

}   

  

class TestThread extends Thread {   

    public void run() {   

        while(true) {   

            System.out.println("TestThread: "+Thread.currentThread().getName() + " is running");   

        }   

    }   

}

这种直接联合,2个线程就完全成了一个线程了。

b,条件联合:

public class ThreadDemo {   

    public static void main(String[] args) {   

        Thread t = new TestThread();   

//      t.setDaemon(true);   

        t.start();   

        int i=0;   

        while(true) {   

            System.out.println("main(): "+Thread.currentThread().getName() + " is running");   

            if(i++ ==10000) {   

                try {   

                    t.join();   

                } catch (InterruptedException e) {   

                    e.printStackTrace();   

                }   

            }   

        }   

    }   

}   

  

class TestThread extends Thread {   

    public void run() {   

        while(true) {   

            System.out.println("TestThread: "+Thread.currentThread().getName() + " is running");   

        }   

    }   

}

当main线程中工作10000下后,把线程TestThread 联合进来,实际上就是main线程运行10000下后,一直等到TestThread 完成后,再运行。

c,联合10秒和分开:

public class ThreadDemo {   

    public static void main(String[] args) {   

        Thread t = new TestThread();   

//      t.setDaemon(true);   

        t.start();   

        int i=0;   

        while(true) {   

            System.out.println("main(): "+Thread.currentThread().getName() + " is running");   

            if(i++ ==10000) {   

                try {   

                    t.join(10000);   

                } catch (InterruptedException e) {   

                    e.printStackTrace();   

                }   

            }   

        }   

    }   

}   

  

class TestThread extends Thread {   

    public void run() {   

        while(true) {   

            System.out.println("TestThread: "+Thread.currentThread().getName() + " is running");   

        }   

    }   

}

当main线程运行10000下后,与TestThread 联合10秒,其实就是让TestThread 运行10秒,然后在分别运行。

Java 多线程例子4 继承Thread 实现Runnable

class TestThread extends Thread {   

    public void run() {   

        while(true) {   

            System.out.println("TestThread: "+Thread.currentThread().getName() + " is running");   

        }   

    }   

}   

class ThreadDemo {   

    public static void main(String[] args) {   

        TestThread t = new TestThread();   

        new Thread(t).start();   

        new Thread(t).start();   

        new Thread(t).start();   

        new Thread(t).start();   

    }   

}   

  

class TestThread implements Runnable {   

    int tickets = 100;   

    public void run() {   

        while(true) {   

            if(tickets<0)   

                break;   

            System.out.println(Thread.currentThread().getName() + " is saling " + tickets--);   

        }   

    }   

}

这里模拟4个窗口,一起卖100张车票。新建一个线程可以通过继承Thread类或实现Runnable,几乎所有的线程实现都可以通过实现Runnable完成,而且该方法适合多个相同线程去处理同一个资源的情况,把虚拟的线程和数据有效分离,较好地体现了面向对象的设计思想。上面4个窗口一起卖100张票的例子有继承Thread的方法就不是太好实现。

Java 多线程例子5 实际例子的讨论

1, 网络聊天程序,如QQ。

发送信息和接受信息肯定要连个线程,你不可能自己输入发送信息的时候就不能接受对方的信息了。 

2,图形界面程序。

要说多线程用的最多的恐怕就要数图形程序了,图形程序每隔一段时间就要刷新一次,要不然大家是看不到图形的。 

3,www网络服务器。

不可能每个网页只能在一个时间内让一个访问,实际上,网络服务器会为每个访问者建立一个专属的线程。 

其实,线程在计算机中的运行中本没有实现真正的并行运行,最终还是由cpu交替运行这些线程,所以我觉得如果说对于单CPU来说的话多线程提高了效率那是不对的。那么在什么样的情况下需要使用多线程呢,现在我先总结成,在一个程序中需要有多个事情长期存在,而且这些事情都会存在等待的情况,我们就可以采用多线程的技术来实现貌似这些事情都并行的程序了。 

看上面举得例子是不是这种情况呢?

第一,网络聊天程序,讨论的是发送信息和接受信息这两件事,首先这两件事都是长期存在的,不可能发了一个信息就不发了,然后看是不是这两件事是不是都存在等待呢,发送不可能总在发送吧,同样对方也不可能总在发送这边就不可能总在接受了,两件事情都存在等待,发送是要等待用户输入信息,接受要等待对方发送信息。 

第二,图形界面,比如一个图形界面中有两个按钮,就像两件事情,这两个按钮都长时间存在,而且都在等待用户的按键。 

第三,网络服务器 多个用户长时间访问这个网页,网络服务器等待这些用户与服务器交互。 

总结:需要用多线程 = 多任务共存长时间 + 多任务存在等待时间

Java 多线程例子6 线程安全 线程同步 同步代码块 同步函数

线程安全

出现线程安全就是在使用多线程的时候程序出现了不期望的结果。

怎样思考线程安全:线程中任何一步运行完都可能交出CPU的控制权。

class ThreadDemo {   

    public static void main(String[] args) {   

        TestThread t = new TestThread();   

        new Thread(t).start();   

        new Thread(t).start();   

        new Thread(t).start();   

        new Thread(t).start();   

    }   

}   

  

class TestThread implements Runnable {   

    int tickets = 100;   

    public void run() {   

        while(true) {   

            if(tickets<=0)   

                break;   

            //try{Thread.sleep(10);}catch(Exception e) {}   

            System.out.println(Thread.currentThread().getName()    

                + " is saling " + tickets--);   

        }   

    }   

}

例子展示了四个售票员一起卖这100张票,那么卖出同样序号的票是我们不期望看到了情况吧,上面已经提到了,分析线程安全的最基本的方法就是认为线程运行的时候任何情况下都可以交出CPU的控制权,上面一共启动了4个线程,现在假设tickets的值为1时,线程1在运行完“if(tickets<=0)”后交出CPU,后线程2得到了CPU,卖出了票1,后线程1重新得到了CPU,又卖出了票1或0。当然,上述情况是我们假设在什么情况下会出现象这样的线程安全的问题,在一般情况,我们运行这个程序好几次也不能看出这样的线程安全问题,那我们怎么确定这个问题呢?我们可以用“sleep(100)”来主动交出CPU来验证我们的想法:去掉上面注释的sleep再运行程序,得到

运行结果 写道

Thread-1 is saling 2 
Thread-2 is saling 1 
Thread-3 is saling 0 
Thread-0 is saling -1 
Thread-1 is saling -2 

卖出了0、-1和-2的票,证明上述这种写法是存在线程安全的。

线程同步

为了解决线程安全的问题,就要引入线程同步。

class ThreadDemo {   

    public static void main(String[] args) {   

        TestThread t = new TestThread();   

        new Thread(t).start();   

        new Thread(t).start();   

        new Thread(t).start();   

        new Thread(t).start();   

    }   

}   

  

class TestThread implements Runnable {   

    int tickets = 100;   

    String str = "";   //此时str为公共对象

    public void run() {   

        while(true) {   

            synchronized(str) {   

                if(tickets<=0)   

                    break;   

                //try{Thread.sleep(10);}catch(Exception e) {}   

                System.out.println(Thread.currentThread().getName()    

                    + " is saling " + tickets--);   

            }   

        }   

    }   

}

 在上面的代码中加入synchronized,就可以实现线程同步了。

运行结果 写道

hread-2 is saling 5 
hread-3 is saling 4 
hread-1 is saling 3 
hread-0 is saling 2 
hread-2 is saling 1 

这个线程同步怎么理解呢?这里有个锁旗标的概念,锁旗标可以理解为java中的每一个对象都有个标志位,该标志位开始的状态是1,当执行完synchronized后这个对象的标志位被置为了0,这个过程就说这个线程得到了这个对象的锁旗标,synchronized块运行完之后这个线程会让出这个对象的锁旗标,而每个线程在遇到synchronized是都回查看这个对象的锁旗标在不在,如果不在该线程就会主要让出CPU。

这里还要记住synchronized的对象一定要是多个线程的公共对象,要是各自的对象就不能实现同步了。如下面改变str定义的位置。

class ThreadDemo {   

    public static void main(String[] args) {   

        TestThread t = new TestThread();   

        new Thread(t).start();   

        new Thread(t).start();   

        new Thread(t).start();   

        new Thread(t).start();   

    }   

}   

  

class TestThread implements Runnable {   

    int tickets = 100;   

    public void run() {   

        String str = "";//此时str为私有对象   

        while(true) {   

            synchronized(str) {   

                if(tickets<=0)   

                    break;   

                //try{Thread.sleep(10);}catch(Exception e) {}   

                System.out.println(Thread.currentThread().getName()    

                    + " is saling " + tickets--);   

            }   

        }   

    }   

}

结果为 写道

Thread-1 is saling 2 
Thread-2 is saling 1 
Thread-3 is saling 0 
Thread-0 is saling -1 
Thread-1 is saling -2

 另外,在运行加入了synchronized同步块的程序的时会发现速度明显比没有同步块的程序要慢的多,所以在确定不会出现线程安全问题的程序中不要加入同步块,就像我们经常先使用Vector还是有ArrayList呢?它们两个的功能基本是完全一样的都是List,而Vector中的函数考虑了线程同步,ArrayList没有,这下就非常明显了,如果需要保证线程安全是就用Vector,不需要就用ArrayList效率高些。

同步函数

同步函数实现

class ThreadDemo {   

    public static void main(String[] args) {   

        TestThread t = new TestThread();   

        new Thread(t).start();   

        new Thread(t).start();   

        new Thread(t).start();   

        new Thread(t).start();   

    }   

}   

  

class TestThread implements Runnable {   

    int tickets = 100;   

    public void run() {   

        while(true) {   

            sale();   

        }   

    }   

    public synchronized void sale() {   

        if(tickets<=0)   

                return;   

        try{Thread.sleep(10);}catch(Exception e) {}   

        System.out.println(Thread.currentThread().getName()    

                    + " is saling " + tickets--);   

    }   

}

同步函数实际上同步的是this对象,这样如果要想某一个同步块和一个同步函数同步,就在同步块中使用this对象。

Java 多线程例子7 线程安全 死锁

死锁:在多个线程里对多个同步对象具有循环依赖时常会出现死锁。最简单的死锁例子就是线程一得到了A对象的锁旗标想得到B对象的锁旗标,线程二得到了B对象的锁旗标想得到A对象的锁旗标,这样线程一和线程二就形成了死锁。

class ThreadDemo {   

    public static void main(String[] args) {   

        TestThread t = new TestThread();   

        new Thread(t).start();   

        try{Thread.sleep(10);}catch(Exception e) {}   

        t.flag = true;   

        new Thread(t).start();   

    }   

}   

  

class TestThread implements Runnable {   

    boolean flag = false;   

    String A=new String("");   

    String B=new String("");   

//  String A="";   

//  String B="";   

       

    public void run() {   

        System.out.println(A==B);   

        if(flag) {   

            while(true) {   

                synchronized(A) {   

                    try{Thread.sleep(100);}catch(Exception e) {}   

                    synchronized(B) {}   

                }   

                System.out.println("AA...running...");   

            }   

        } else  {   

            while(true) {   

                synchronized(B) {   

                    try{Thread.sleep(100);}catch(Exception e) {}   

                    synchronized(A) {}   

                }   

                System.out.println("BB...running...");   

                }   

        }   

    }   

}

这里启动了两个线程,两个线程都循环想要得到A对象和B对象的锁旗标。

在试验这个例子的时候,还遇到了一个有意思的问题:刚开始我用的A和B对象是这么写的A="";B="";结果死活实验不出来死锁问题,这倒是挺奇怪的。结果最后发现原来这时候A和B引用了同一个对象,这是更java中对字符串常量的处理有关系,A="";时,java会在堆中建立一个字符串常量,这个字符串常量为空,由A引用,在B="",java发现字符串常量中有这么一个空字符串常量就不会新建了。

Java 多线程例子8 线程状态

在JDK的电子书中搜索Thread.State可以找到。

public static enum Thread.Stateextends Enum<Thread.State>线程状态。线程可以处于下列状态之一: 

1.NEW 
至今尚未启动的线程的状态。 

2.RUNNABLE 
可运行线程的线程状态。处于可运行状态的某一线程正在 Java 虚拟机中运行,但它可能正在等待操作系统中的其他资源,比如处理器。 

3.BLOCKED 
受阻塞并且正在等待监视器锁的某一线程的线程状态。处于受阻塞状态的某一线程正在等待监视器锁,以便进入一个同步的块/方法,或者在调用 Object.wait 之后再次进入同步的块/方法。 

4.WAITING 
某一等待线程的线程状态。某一线程因为调用下列方法之一而处于等待状态:

· 不带超时值的 Object.wait 

· 不带超时值的 Thread.join 


LockSupport.park 
处于等待状态的线程正等待另一个线程,以执行特定操作。 例如,已经在某一对象上调用了 Object.wait() 的线程正等待另一个线程,以便在该对象上调用 Object.notify() 或 Object.notifyAll()。已经调用了 Thread.join() 的线程正在等待指定线程终止。 

5.TIMED_WAITING具有指定等待时间的某一等待线程的线程状态。某一线程因为调用以下带有指定正等待时间的方法之一而处于定时等待状态:

· Thread.sleep 

· 带有超时值的 Object.wait 

· 带有超时值的 Thread.join 

· LockSupport.parkNanos 

· LockSupport.parkUntil 


6.TERMINATED 
已终止线程的线程状态。线程已经结束执行。 

注意:在给定时间点上,一个线程只能处于一种状态。这些状态是虚拟机状态,它们并没有反映所有操作系统线程状态。 

为了展现线程在运行时的状态及其转换,我画了下面这个图:



Java 多线程例子9 线程之间通信 wait notify notifyAll

程序实现了一个生产者和一个消费者,还有一个buffer用于存放生产出来的一个对象,buffer中只可以存放一个对象,buffer有一个标志位bFull,如果标志位为true表示buffer里有数值,如果bFull为false表示没有数值。buffer中的对象有两个属性,在多线程中如果不处理同步的话,可能出现属性不对应的情况。

wait:告诉当前线程放弃监视器并进入睡眠状态,直到其他线程进入同一监视器并调用notify为止。

notify:唤醒同一对象监视器中调用wait的第一线程。用于类似饭馆有一个空位子后通知所有等候就餐的顾客中的第一位可以入座的情况。

notifyAll:唤醒同一对象监视器中调用wait的所有线程,具有最高优先级的线程首先被唤醒并执行。用于类似某个不定期的培训班终于招生满额后,通知所有学员都来上课的情况。

从上面明显可以看出wait、notify和notifyAll只能在synchronized方法中调用,记住一个对象的notify只能够唤醒被同一个对象wait的线程。

class ThreadDemo {   

    public static void main(String[] args) {   

        Buffer buf = new Buffer();   

        new Producer(buf).start();   

        new Consumer(buf).start();   

    }   

}   

class Producer extends Thread {   

    private Buffer buf;   

    public Producer(Buffer buf) {   

        this.buf = buf;   

    }   

    public void run() {   

        boolean odd = false;   

        while(true) {   

            synchronized(buf) {   

                if(buf.bFull)   

                    try{buf.wait();}catch(Exception e) {}   

                if(odd) {   

                    buf.name="jack";       

                    try{Thread.sleep(100);}catch(Exception e) {}   

                    buf.sex="female";   

                } else {   

                    buf.name="lucy";       

                    try{Thread.sleep(100);}catch(Exception e) {}   

                    buf.sex="male";   

                }   

                buf.bFull = true;   

                buf.notify();   

            }   

            odd = !odd;   

        }   

    }   

}   

class Consumer extends Thread {   

    private Buffer buf;   

    public Consumer(Buffer buf) {   

        this.buf = buf;   

    }   

    public void run() {   

        while(true) {   

            synchronized(buf) {   

                if(!buf.bFull)   

                    try{buf.wait();}catch(Exception e) {}   

                //try{Thread.sleep(100);}catch(Exception e) {}   

                System.out.println(buf.name + " : " + buf.sex);   

                buf.bFull = false;   

                buf.notify();   

            }   

        }   

    }   

}   

class Buffer {   

    boolean bFull = false;   

    String name = "Unkown";   

    String sex = "Unkown";   

}

结果 写道

lucy : male 
jack : female 
lucy : male 
jack : female 
lucy : male 
jack : female

面前对象 同步函数

class ThreadDemo {   

    public static void main(String[] args) {   

        Buffer buf = new Buffer();   

        new Producer(buf).start();   

        new Consumer(buf).start();   

    }   

}   

class Producer extends Thread {   

    private Buffer buf;   

    public Producer(Buffer buf) {   

        this.buf = buf;   

    }   

    public void run() {   

        boolean odd = false;   

        while(true) {   

            if(odd) {   

                buf.put("jack","female");   

            } else {   

                buf.put("lucy","male");   

            }   

            odd = !odd;   

        }   

    }   

}   

class Consumer extends Thread {   

    private Buffer buf;   

    public Consumer(Buffer buf) {   

        this.buf = buf;   

    }   

    public void run() {   

        while(true) {   

            buf.get();   

        }   

    }   

}   

class Buffer {   

    private boolean bFull = false;   

    private String name = "Unkown";   

    private String sex = "Unkown";   

       

    public synchronized void put(String name, String sex) {   

        if(bFull)   

            try{wait();}catch(Exception e) {}   

        this.name = name;   

        this.sex = sex;   

        bFull = true;   

        notify();   

    }   

    public synchronized void get() {   

        if(!bFull)   

            try{wait();}catch(Exception e) {}   

        System.out.println(name + " : " + sex);   

        bFull = false;   

        notify();   

    }   

}

Java 多线程例子10 控制线程的生命 stop

在Thread类中stop已经不推荐大家使用了,因为使用stop停止的线程不安全,它并不会释放被该线程锁定的对象的锁旗标,这样其它线程如果也想要得到该对象的锁旗标就永远得不到了,形成死锁了。

利用标志位控制线程的生命周期:

public class threadtest {

public static void main(String[] args) {   

        Thread1 t = new Thread1();   

        t.start();   

        try{Thread.sleep(1);}catch(Exception e){};   

        for(int i=0; i<10; i++) {   

            System.out.println("main"  

                    + " is running.");   

            if(i==5)   

                t.stopMe();   

        }   

    }   

}   

class Thread1 extends Thread {   

    private boolean bStop = false;   

    public void stopMe() {   

        this.bStop = true;   

    }   

    public void run() {   

        while(!bStop) {   

            System.out.println(Thread.currentThread().getName()    

                    + " is running.");   

        }   

    }   

}

作者:m13666368773 发表于2012-2-9 17:43:50 原文链接
阅读:9 评论:0 查看评论

相关 [java thread 多线程] 推荐:

Java Thread多线程

- - CSDN博客推荐文章
Java Thread多线程. Java 多线程例子1 小例子. super("zhuyong");//设置线程的名字,默认为“TestThread”. Java 多线程例子2 前台线程(用户线程) 后台线程(守护线程 ). 1,setDaemon(true)后就是后台线程(守护线程 ),反之就是前台线程(用户线程).

在 TDA 工具里看到 Java Thread State 的第一反应是

- - 博客园_旁观者-郑昀
使用 TDA 工具,看到大量 Java Thread State 的第一反应是:. 1,线程状态为“waiting for monitor entry”:. 意味着它  在等待进入一个临界区 ,所以它在”Entry Set“队列中等待. 此时线程状态一般都是 Blocked:. 2,线程状态为“waiting on condition”:.

三个实例演示 Java Thread Dump 日志分析

- - 博客园_旁观者
jstack Dump 日志文件中的线程状态. dump 文件里,值得关注的线程状态有:. Deadlock(重点关注) . 执行中,Runnable   . Waiting on condition(重点关注) . Waiting on monitor entry(重点关注). 暂停,Suspended.

Java多线程之synchronized

- - CSDN博客推荐文章
这里通过三个测试类阐述了synchronized应用的不同场景. 首先是最基本的synchronized Method的使用.  * @see 概述:Java中的每个对象都有一个锁(lock)或者叫做监视器(monitor) .  * @see 说明:当synchronized关键字修饰一个方法时,则该方法为同步方法 .

java多线程总结

- - Java - 编程语言 - ITeye博客
在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口. 对于直接继承Thread的类来说,代码大致框架是:. class 类名 extends Thread{. * @author Rollen-Holt 继承Thread类,直接调用run方法.             System.out.println(name + "运行     " + i);.

Java多线程学习

- - CSDN博客编程语言推荐文章
  线程是一种轻量级的进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在于线程没有独立的存储空间,而是和所属进程中的其它线程共享一个存储空间,这使得线程间的通信远较进程简单. 即多个线程可以同时执行,就像有多条流水线一样,可以同时进行工作,是并发执行的.   程序是由进程组成的,进程是由线程组成的.

Java多线程(二)同步

- - CSDN博客编程语言推荐文章
如果你的java基础较弱,或者不大了解java多线程请先看这篇文章 java多线程(一)线程定义、状态和属性. 同步一直是java多线程的难点,在我们做android开发时也很少应用,但这并不是我们不熟悉同步的理由. 希望这篇文章能使更多的人能够了解并且应用java的同步. 在多线程的应用中,两个或者两个以上的线程需要共享对同一个数据的存取.

[Java] Java 多线程案例分析

- - V2EX
现要从 hbase中导出 2016 年整年的,大约 10w只股票行情数据,数据总量约 100t. 汇总到 hdfs中供需求方使用. 已知数据量规模大概是 100t,那么单台机器处理肯定不是不行的,先不说大多数磁盘都没这么大,即便磁盘有这么大,单台机器处理对于内存和 cpu 要求也很高,所以我们将问题一般化,使用数量有限的低配机器.

Java 多线程内存模型

- - ITeye博客
Java 多线程内存模型.       Java虚拟机规范中试图定义一种Java内存模型(Java Memory Model,JMM)来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的并发效果. 在此之前,主流程序怨言(如C/C++等)直接使用物理硬件(或者说操作系统的内存模型),因此,会由于不同的平台上内存模型差异,导致程序在一套平台上并发完成正常,而在另一套平台上并发访问却经常出错,因此经常需要针对不同的平台来编写程序.

Java多线程之wait()和notify()

- - CSDN博客推荐文章
直接看测试代码吧,细节之处,详见注释.  * Java多线程之wait()和notify()的妙用 .  * @see 问题:同时启动两个线程和同时启动四个线程,控制台打印结果是不同的 .  * @see      同时启动两个线程时,控制台会很规律的输出1010101010101010 .  * @see      同时启动四个线程时,控制台起初会规律的输出10101010,一旦某一刻输出一个负数,那么后面的输出就会"一错再错" .