java多线程知识点总结

多线程(英语:multithreading)

每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。线程可以在程序里独立执行,由操作系统负责多个线程的调度和执行。

线程和进程的区别在于,子进程和父进程有不同的代码和数据空间,而多个线程则共享数据空间,每个线程有自己的执行堆栈和程序计数器为其执行上下文.多线程主要是为了节约CPU时间,充分利用了CPU的空闲时间片,线程的运行中需要使用计算机的内存资源和CPU。

优点

·使用线程可以把占据时间长的 程序中的 任务放到 后台去处理
·用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
· 程序的运行速度可能加快
·在一些等待的 任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种 情况下可以释放一些珍贵的资源如 内存占用等等。

缺点

·如果有大量的线程,会影响性能,因为 操作系统需要在它们之间切换。
·更多的线程需要更多的 内存空间。
·线程可能会给 程序带来更多“bug”,因此要小心使用。
·线程的中止需要考虑其对 程序运行的影响。
·通常块模型数据是在多个线程间共享的,需要防止线程死锁 情况的发生。


JAVA中的线程

一个Java应用总是从main()方法开始运行,mian()方法运行在一个线程内,它被称为主线程。

main方法其实也是一个线程。在java中所以的线程都是同时启动的,至于什么时候,哪个先执行,完全看谁先得到CPU的资源。

 

java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,每一个jVM实习在就是在操作系统中启动了一个进程。



java中创建线程的两种方式:继承Thread和实现Runnable接口
实现Runnable接口适用情况: 资源共享+多个线程执行相同代码。
资源共享例子:购票系统,多个线程对共享资源进行读写。
执行相同代码例子:购票系统。new Thread(obj);obj是实现runnable的对象。

java多线程购票系统代码:
class SellThread implements Runnable
         {
            int tickets=100;//对共享资源的访问
            public synchronized void sell()//用关键字sychronized,标志同步方法
            {
                  if(tickets>0)
                  {
                     try
                     {
                        Thread.sleep(10);
                     }
                     catch(Exception e)
                     {
                        e.printStackTrace();
                     }
                  }
               }
           
         public void run()
         {
            while(true)
            {
               sell();
            }
         }
}
public class TicketSystem
{
   public static void main(String[] args)
   {
      SellThread st=new SellThread();
      new Thread(st).start();//多个购票窗口执行相同操作
      new Thread(st).start();//多个购票窗口执行相同操作
      new Thread(st).start();//多个购票窗口执行相同操作
   }
}

继承Thread类适用情况:
多个线程执行不同的代码,则分别继承重写Thread类。
如:生产者和消费者例子。
很多后台服务程序并发控制的基本原理都可以归纳为生产者 / 消费者模式。
用wait() / notify()方法实现生产者消费者例子
(代码来自 http://blog.csdn.net/monkey_d_meng/article/details/6251879,感谢原作者
[java] view plain copy
import java.util.LinkedList;  
  
/** 
 * 仓库类Storage实现缓冲区 
 *  
 * Email:[email protected] 
 *  
 * @author MONKEY.D.MENG 2011-03-15 
 *  
 */  
public class Storage  
{  
    // 仓库最大存储量  
    private final int MAX_SIZE = 100;  
  
    // 仓库存储的载体  
    private LinkedList list = new LinkedList();  
  
    // 生产num个产品  
    public void produce(int num)  
    {  
        // 同步代码段  
        synchronized (list)  
        {  
            // 如果仓库剩余容量不足  
            while (list.size() + num > MAX_SIZE)  
            {  
                System.out.println("【要生产的产品数量】:" + num + "/t【库存量】:"  
                        + list.size() + "/t暂时不能执行生产任务!");  
                try  
                {  
                    // 由于条件不满足,生产阻塞  
                    list.wait();  
                }  
                catch (InterruptedException e)  
                {  
                    e.printStackTrace();  
                }  
            }  
  
            // 生产条件满足情况下,生产num个产品  
            for (int i = 1; i <= num; ++i)  
            {  
                list.add(new Object());  
            }  
  
            System.out.println("【已经生产产品数】:" + num + "/t【现仓储量为】:" + list.size());  
  
            list.notifyAll();  
        }  
    }  
  
    // 消费num个产品  
    public void consume(int num)  
    {  
        // 同步代码段  
        synchronized (list)  
        {  
            // 如果仓库存储量不足  
            while (list.size() < num)  
            {  
                System.out.println("【要消费的产品数量】:" + num + "/t【库存量】:"  
                        + list.size() + "/t暂时不能执行生产任务!");  
                try  
                {  
                    // 由于条件不满足,消费阻塞  
                    list.wait();  
                }  
                catch (InterruptedException e)  
                {  
                    e.printStackTrace();  
                }  
            }  
  
            // 消费条件满足情况下,消费num个产品  
            for (int i = 1; i <= num; ++i)  
            {  
                list.remove();  
            }  
  
            System.out.println("【已经消费产品数】:" + num + "/t【现仓储量为】:" + list.size());  
  
            list.notifyAll();  
        }  
    }  
  
    // get/set方法  
    public LinkedList getList()  
    {  
        return list;  
    }  
  
    public void setList(LinkedList list)  
    {  
        this.list = list;  
    }  
  
    public int getMAX_SIZE()  
    {  
        return MAX_SIZE;  
    }  
}  
/** 
 * 生产者类Producer继承线程类Thread 
 *  
 * Email:[email protected] 
 *  
 * @author MONKEY.D.MENG 2011-03-15 
 *  
 */  
public class Producer extends Thread  
{  
    // 每次生产的产品数量  
    private int num;  
  
    // 所在放置的仓库  
    private Storage storage;  
  
    // 构造函数,设置仓库  
    public Producer(Storage storage)  
    {  
        this.storage = storage;  
    }  
  
    // 线程run函数  
    public void run()  
    {  
        produce(num);  
    }  
  
    // 调用仓库Storage的生产函数  
    public void produce(int num)  
    {  
        storage.produce(num);  
    }  
  
    // get/set方法  
    public int getNum()  
    {  
        return num;  
    }  
  
    public void setNum(int num)  
    {  
        this.num = num;  
    }  
  
    public Storage getStorage()  
    {  
        return storage;  
    }  
  
    public void setStorage(Storage storage)  
    {  
        this.storage = storage;  
    }  
}  
/** 
 * 消费者类Consumer继承线程类Thread 
 *  
 * Email:[email protected] 
 *  
 * @author MONKEY.D.MENG 2011-03-15 
 *  
 */  
public class Consumer extends Thread  
{  
    // 每次消费的产品数量  
    private int num;  
  
    // 所在放置的仓库  
    private Storage storage;  
  
    // 构造函数,设置仓库  
    public Consumer(Storage storage)  
    {  
        this.storage = storage;  
    }  
  
    // 线程run函数  
    public void run()  
    {  
        consume(num);  
    }  
  
    // 调用仓库Storage的生产函数  
    public void consume(int num)  
    {  
        storage.consume(num);  
    }  
  
    // get/set方法  
    public int getNum()  
    {  
        return num;  
    }  
  
    public void setNum(int num)  
    {  
        this.num = num;  
    }  
  
    public Storage getStorage()  
    {  
        return storage;  
    }  
  
    public void setStorage(Storage storage)  
    {  
        this.storage = storage;  
    }  
}  
/** 
 * 测试类Test 
 *  
 * Email:[email protected] 
 *  
 * @author MONKEY.D.MENG 2011-03-15 
 *  
 */  
public class Test  
{  
    public static void main(String[] args)  
    {  
        // 仓库对象  
        Storage storage = new Storage();  
  
        // 生产者对象  
        Producer p1 = new Producer(storage);  
        Producer p2 = new Producer(storage);  
        Producer p3 = new Producer(storage);  
        Producer p4 = new Producer(storage);  
        Producer p5 = new Producer(storage);  
        Producer p6 = new Producer(storage);  
        Producer p7 = new Producer(storage);  
  
        // 消费者对象  
        Consumer c1 = new Consumer(storage);  
        Consumer c2 = new Consumer(storage);  
        Consumer c3 = new Consumer(storage);  
  
        // 设置生产者产品生产数量  
        p1.setNum(10);  
        p2.setNum(10);  
        p3.setNum(10);  
        p4.setNum(10);  
        p5.setNum(10);  
        p6.setNum(10);  
        p7.setNum(80);  
  
        // 设置消费者产品消费数量  
        c1.setNum(50);  
        c2.setNum(20);  
        c3.setNum(30);  
  
        // 线程开始执行  
        c1.start();  
        c2.start();  
        c3.start();  
        p1.start();  
        p2.start();  
        p3.start();  
        p4.start();  
        p5.start();  
        p6.start();  
        p7.start();  
    }  
}  
【要消费的产品数量】:50   【库存量】:0 暂时不能执行生产任务!  
【要消费的产品数量】:30   【库存量】:0 暂时不能执行生产任务!  
【要消费的产品数量】:20   【库存量】:0 暂时不能执行生产任务!  
【已经生产产品数】:10    【现仓储量为】:10  
【要消费的产品数量】:20   【库存量】:10    暂时不能执行生产任务!  
【要消费的产品数量】:30   【库存量】:10    暂时不能执行生产任务!  
【要消费的产品数量】:50   【库存量】:10    暂时不能执行生产任务!  
【已经生产产品数】:10    【现仓储量为】:20  
【要消费的产品数量】:50   【库存量】:20    暂时不能执行生产任务!  
【要消费的产品数量】:30   【库存量】:20    暂时不能执行生产任务!  
【已经消费产品数】:20    【现仓储量为】:0  
【已经生产产品数】:10    【现仓储量为】:10  
【已经生产产品数】:10    【现仓储量为】:20  
【已经生产产品数】:80    【现仓储量为】:100  
【要生产的产品数量】:10   【库存量】:100   暂时不能执行生产任务!  
【已经消费产品数】:30    【现仓储量为】:70  
【已经消费产品数】:50    【现仓储量为】:20  
【已经生产产品数】:10    【现仓储量为】:30  
【已经生产产品数】:10    【现仓储量为】:40   
    
看完上述代码,对 wait() / notify() 方法实现的同步有了了解。你可能会对 Storage 类中为什么要定义 public void produce(int num); public void consume(int num); 方法感到不解,为什么不直接在生产者类 Producer 和消费者类 Consumer 中实现这两个方法,却要调用 Storage 类中的实现呢?淡定,后文会有解释。我们先往下走。


wait()、notify()、notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态。

这三个方法最终调用的都是jvm级的native方法。随着jvm运行平台的不同可能有些许差异。
    如果对象调用了wait方法就会使
持有该对象的线程把该对象的控制权交出去,然后处于等待状态。
    如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。
    如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。



有朋友可能会有疑问:为何这三个不是Thread类声明中的方法,而是Object类中声明的方法(当然由于Thread类继承了Object类,所以Thread也可以调用者三个方法)?其实这个问题很简单,由于每个对象都拥有monitor(即锁),

所以

让当前线程等待某个对象的锁,当然应该通过这个对象来操作了。而不是用当前线程来操作,因为当前线程可能会等待多个线程的锁,如果通过线程来操作,就非常复杂了。


任何一个对象都有锁,wait(),notify(),notifyall()方法

当前线程必须拥有这个对象的monitor(即锁)

,如果调用某个对象的wait()方法,当前线程必须拥有这个对象的monitor(即锁),因此调用wait()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法)。


对象的控制权就是对象的锁。

注:拥有这个对象锁的线程才能运行运行其中synchronized方法,也即拥有这个对象控制权的线程才能执行synchrozied方法。进而,拥有了控制权,才能用wait()释放控制权

 


synchronized关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。

当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。

当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。

当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。

当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。


     四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。



你可能感兴趣的:(JAVA,SE,JAVA,EE)