zoukankan      html  css  js  c++  java
  • java 多线程 小结

    前面有篇博文是小结c#的多线程的 http://www.cnblogs.com/sylvanas2012/archive/2012/07/26/2610591.html

    java有点不同,实现多线程有两种方式:继承类Thread, 和 实现接口Runnable。

    thread类有一个run函数,它是线程的入口,当启动一个新线程是,就从这个函数开始执行;

    View Code
    public class ThreadTest  extends Thread{
    
        public void run()
        {
            for (int i=0;i<5;i++)
            {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+" "+i);
            }
        }
        
        public static void main(String[] args)
        {
            ThreadTest test1 = new ThreadTest();
            ThreadTest test2 = new ThreadTest();
            
            test1.start();
            test2.start();
        }
    }

    注意线程是调用start()来开始的。

    Runnable有一点点不同,实现这个类的时候和Thread一样,但是创建线程的时候还是放入一个Thread中创建:

    View Code
    public class RunnableTest implements Runnable
    {
    
        private int cnt;
        
        public RunnableTest(int n)
        {
            super();
            cnt = n;
        }
        
        public void run()
        {
            for (int i=0;i<5;i++)
            {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+" "+i+" "+--cnt);
            }
        }
        
        public static void main(String[] args)
        {
            RunnableTest t = new RunnableTest(10);
            Thread ta = new Thread(t);
            Thread tb = new Thread(t);
            
            ta.start();
            tb.start();
        }
    }

     Thread和Runnable基本用法都是差不多的,但是从上面的例子可以看出,Runnable比较方便进程间数据的共享(公用了一个cnt计量单位),所以一样都使用Runnable。
    线程常用的几个函数:

    join():  强制等待线程执行完毕。 例如如果在主线程里面加一句ta.join(),那么主线程会一直等待ta执行返回才接着执行后面的代码。但是在join之前已经创建的其他线程,则不会受影响,继续执行。

    interrupt(): 挺有意思的一个函数,如果线程在执行sleep()函数 ,则打断它(以让sleep()函数抛出一个异常的方式中断),执行后面的语句。

    setDaemon(true):设置为守护进程。守护进程的优先级是最低的,如果一个程序只剩下守护进程,那么它就中断所有守护进程而退出。 最常见的情况是,如果创建的全部是守护进程,那么当主函数main执行完毕后,就立刻终止所有线程而退出。

    synchronized同步符号用法: 保证同一时刻,某段代码只有一个线程在执行。

    wait()和notify(),notifyAll():让线程等待/唤醒。这两个函数比较奇怪,目前我不是很熟练,要配合synchronized符号使用,请看下面这个生产者-消费者例子(网上直接贴来的,写的挺好的):

    View Code
    public class tt {
    
        public static void main(String[] args) {
            Storage s = new Storage();
            Producer p = new Producer(s);
            Consumer c = new Consumer(s);
            Thread tp = new Thread(p);
            Thread tc = new Thread(c);
            tp.start();
            tc.start();
    
        }
    }
    
    class Consumer implements Runnable {//消费者    
        Storage s = null;
        public Consumer(Storage s){
            this.s = s;
        }
        public void run() {
            for(int i=0; i<20; i++){
                Product p = s.pop();//取出产品
                try {
                    Thread.sleep((int)(Math.random()*1500));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
        }
    
    }
    
    class Producer implements Runnable {//生产者
        Storage s = null;
        
        public Producer(Storage s){
            this.s = s;
        }
    
        public void run() {
            for(int i=0; i<20; i++){
                Product p = new Product(i);
                s.push(p);    //放入产品
    //            System.out.println("生产者放入:" + p);
                try {
                    Thread.sleep((int)(Math.random()*1500));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
        }
    }
    
    class Product {
        int id;
        
        public Product(int id){
            this.id = id;
        }
        
        public String toString(){//重写toString方法
            return "产品:"+this.id;
        }
    }
    
     
    class Storage {
        int index = 0;
        Product[] products = new Product[5];
        
        public synchronized void push(Product p){//放入
            while(index==this.products.length){
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            this.products[index] = p;
            System.out.println("生产者放入"+index+"位置:" + p);
            index++;
            this.notifyAll();
        }
        
        public synchronized Product pop(){//取出
            while(this.index==0){
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            index--;
            this.notifyAll();
            System.out.println("消费者从"+ index+ "位置取出:" + this.products[index]);
            return this.products[index];
        }
    }

     大致流程:生产者每次产生一个产品,消费者一次消费一个产品; 仓库容量有限,当满存的时候,生产者就需要等待,直到有消费者消费,才被唤醒; 如果仓库是空的,那么消费者就不能消费,要等待,知道生产者生产出一个产品,并唤醒消费者。

  • 相关阅读:
    MyEclipse中的几种查找方法
    WebLogic初学笔记
    CountDownLatch源码分析
    linux--句柄相关
    linux命令--wc
    Spring源码解析(九)--再来说说三级缓存
    定位JVM内存泄漏常用命令和方法
    Mybatis整合Spring之MapperFactoryBean怎么拿到的SqlSessionFactory
    Mybatis3.3.0 Po类有LocalDateTime字段报错
    时间范围查询优化技巧
  • 原文地址:https://www.cnblogs.com/sylvanas2012/p/2810594.html
Copyright © 2011-2022 走看看