生活不止眼前的枸杞,还有远方的西洋参

痛饮狂歌空度日,飞扬跋扈为谁雄.

多线程

先说一下如何学习一门语言和技术

  1. 了解语言背景,特点.

  2. 语法

  3. 通用小程序

  4. 函数和对象

  5. 第三方类库,插件组件,框架

  6. 开发项目

实现多线程的两种方式:

  1. 继承Thread类
    1. 自定义MyThread继承Thread
    2. 在MyThread中重写run()方法
    3. 创建MyThread类对象
    4. 启动线程对象
    5. 实例:创建SellTicket.java和SellTicketDemo.java类
       1 public class SellTicket implements Runnable {
       2 //定义100张票
       3     private int tickets=100;
       4     //创建锁
       5     private Object obj=new Object();
       6     @Override
       7     public void run() {
       8         synchronized(obj){
       9             while(true){
      10                 if(tickets>0){
      11                     try {
      12                         Thread.sleep(100);
      13                     } catch (InterruptedException e) {
      14                         e.printStackTrace();
      15                     }
      16                     System.out.println(Thread.currentThread().getName()+"正在出售"+(tickets--)+"张票");
      17                 }
      18             }
      19         }
      20     }
      21 }

      SellTicketDemo.java类:

       1 public class SellTicketDemo {
       2  public static void main(String[] args) {
       3     //创建资源对象
       4      SellTicket st1=new SellTicket();
       5      //当前时间,在这里没有意义
       6      SimpleDateFormat df = new SimpleDateFormat("EEE, MMM d, ''yy");  
       7      System.out.println(df.format(System.currentTimeMillis()));   
       8      //创建3个线程对象,传递Myrunable类的对象.
       9      Thread t1=new Thread(st1, "窗口1");
      10      Thread t2=new Thread(st1,"窗口2");
      11      Thread t3=new Thread(st1,"窗口3");
      12      
      13      t2.start();
      14      t1.start();
      15      t3.start();
      16 }
      17 }
  2. 实现Runable接口:
    1. 自定义MyRunable实现Runable接口;
    2. 在MyRunable里面重写run()方法;
    3. 创建MyRunable类的对象;
    4. 创建Thread类的对象,并把3中对象作为构造参数 传递.
          public static void main(String[] args) {
               new Thread(new Thread1()).start();
               try {
                   Thread.sleep(100);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               new Thread(new Thread2()).start();         
          }
          
          /*
           * Thread1实现Runable
           */
          private static class Thread1 implements Runnable
          {
               @Override
               public void run() {
              //由于这里的Thread1和下面的Thread2内部run方法要用同一对象作为监视器,
             //我们这里不能用this,因为在Thread2里面的this和这个Thread1的this不是同一个对象。我们用MultiThread.class这个字节码对象,当前虚拟机里引用这个变量时,指向的都是同一个对象。
              synchronized (MultiThread.class) {
              System.out.println("enter thread1...");
              System.out.println("thread1 is waiting");
              try {
               //释放锁有两种方式,第一种方式是程序自然离开监视器的范围,
               //也就是离开了synchronized关键字管辖的代码范围,
              //另一种方式就是在synchronized关键字管辖的代码内部调用监视器对象的wait方法。这里,使用wait方法释放锁。
               MultiThread.class.wait();
               } catch (InterruptedException e) {
                e.printStackTrace();
                }
                 System.out.println("thread1 is going on...");
                 System.out.println("thread1 is being over!");             
                   }
               }
          }
          
          /*
           * Thread2
           */
          private static class Thread2 implements Runnable
          {
               @Override
               public void run() {
                   synchronized (MultiThread.class) {
                        System.out.println("enter thread2...");
                        System.out.println("thread2 notify other thread can release wait status..");
                //由于notify方法并不释放锁, 即使thread2调用下面的sleep方法休息了10毫秒,
               //但thread1仍然不会执行,因为thread2没有释放锁,所以Thread1无法得不到锁。
                        MultiThread.class.notify();
                        System.out.println("thread2 is sleeping ten millisecond...");
                        try {
                             Thread.sleep(10);
                        } catch (InterruptedException e) {
                             e.printStackTrace();
                        }
                        System.out.println("thread2 is going on...");
                        System.out.println("thread2 is being over!");
                   }
               }
          }    
      
  • 为什么要有两种方式:

    • 实现Runable接口解决了java单继承的局限性,适合多个相同程序的代码去处理同一个资源的情况 ,把线程同程序代码和数据分离,较好 的体现了面向 对象的设计思想.

线程安全的原因:

  1. 是多线程;

  2. 共享数据;

  3. 有多条语句操作数据

解决方案:就是破坏线程不安全的条件,非要在多线程下操作共享数据就只能破坏第三个条件了,把多条语句操作共享数据的代码包成一个代码块,让某个线程在执行 的时候别人不能执行,这里java给我们提供的同步机制:synchronized

1 synchronized(对象){//同步的根本就在对象,该对象如同锁,多个线程同一把锁,
2     代码块
3 }

 

同步的弊端 :当线程特别多时,因为每一个锁都会去判断同步上的锁,这是很浪费资源的,无形中降低了程序运行的效率.

线程安全的类有:

1 1 //线程安全的类
2 2 StringBuffer sb =new StringBuffer();
3 3 Vector<String> v=new Vector<String>)();
4 4 Hashtable<String,String> h=new Hashtable<String,String>();

  原因:就是在这些类中实现了Runable接口,具备了线程安全的特性

使用如下代码可以使类具备线程安全:

1 //线程安全
2 List<String> li=Collections.synchronizedList(new ArrayList<String>());

 

posted on 2018-08-08 11:59  黑夜,我累了  阅读(297)  评论(0编辑  收藏  举报

导航