黑马程序员-多线程

------- android培训java培训、期待与您交流! ----------

Thread.currentThread().getName()方法得到当前程序执行线程的名字

 

创建线程第一种方法:让实现线程类继承Thread类,然后重写run()方法(被继承的Thread的run()方法没有方法体,主要用于执行内容),在主函数中新建出实现线程的类并调用start()方法,就会自动执行run()中的内容

public class ThreadDemo {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       //在主函数调用新建的实现线程的类并start

       new ThreadTest().start();

       while(true){

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

       }

    }

}

    //让线程继承Thread类并复写run方法

    class ThreadTest extends Thread{

 

       @Override

       public void run() {

           // TODO Auto-generatedmethod stub

           while(true){

              System.out.println("run()" + Thread.currentThread().getName());

           }

       }

      

    }

 

后台线程与联合线程:

后台线程TestThread t = new TestThread();

       t.setDaemon(true);//设为后台线程

当没有前台线程运行时,后台线程也随之结束

联合线程线程用join()方法联合,并自动成为当前线程的子线程,先执行完子线程在执行主线程。

注意:join(参数)中的参数是时间,当两个线程合并指定时间后再分为两个不同线程

public class ThreadDemo {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       //在主函数调用新建的实现线程的类并start

       Thread t = new ThreadTest();

       t.start();

       int index = 0;

       while(true){

           if(index++ == 50000)

              try {

                  t.join();

              } catch (InterruptedException e) {

                  // TODO Auto-generatedcatch block

                  e.printStackTrace();

              }

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

       }

    }

}

    //让线程继承Thread类并复写run方法

    class ThreadTest extends Thread{

 

       @Override

       public void run() {

           // TODO Auto-generatedmethod stub

           while(true){

              System.out.println("run()" + Thread.currentThread().getName());

           }

       }

      

    }

创建线程的第二种方法:创建出thread类,并将继承过Runnable的类当做参数传入,与第一种方法一样,覆写run()方法

class TestThread implements Runnable{

public void run(){

}

}

Thread t = new Thread(new TestThread());

 

创建线程两种方法的区别:

继承runnable更适合操作同一资源

 

 

使用Runnable接口创建多线程

1.      适合多个相同程序代码的线程去处理同一资源的情况,把虚拟CPU(线程)同程序的代码、数据有效分离,较好的体现了面向对象的设计思想

2.      可以避免由于Java的单继承特性带来的局限。我们经常碰到这样一种情况,即当我们要将已经继承了某一个类的子类放入多线程中,由于一个类不能同时有两个父类,所以不能继承Thread类的方式,那么,这个类就只能采用实现Runnable

3.      当线程被构造时,需要的代码和数据通过一个对象作为构造函数实参传递进去,这个对象就是一个实现了Runnable接口的类的实例

4.      事实上,几乎所有多线程应用都可用Runnable接口方式

创建多线程的用处:

例子:

1.      网络聊天程序的收发

a)        没有线程的


b)       多线程的


2.      表记录的复制和中途取消

3.      www服务器为一个来访者都建立专线服务

 

有关线程安全性问题:

以售票为例:当还剩最后一张票时,四个售票口可能同时出售…

所以,在线程类中,只能有像独木桥只允许一个线程通过,用synchronized()实现

用synchronized(){}的形式括起来

Synchronized会加大内存的开销,如果确定没有安全性问题就可以不加

注意:要将string放在run()方法的外部

class TestThread implements Runnable/*extendsThread*/{

    //然后重写run()方法

    int tickets = 1000;

    String str = new String("");

    public void run(){

       if(str.equals("method")){

           while(true){

              sale();

           }

       }else{

       while(true){

           synchronized(str){

              if(tickets > 0){

                  try {

                     Thread.sleep(10);

                  } catch (InterruptedException e) {

                     // TODO Auto-generatedcatch block

                     e.printStackTrace();

                  }

                  synchronized (this) {}

              System.out.print("代码:");

              System.out.println("run():"+Thread.currentThread().getName()+"is salling ticket"+tickets--);

                  }

           }

       }

       }

 

    }

}

 

想让代码块与方法同步,必须让代码块中的synchronized参数为this

死锁问题:应尽量使用同一个参数,以避免死锁的发生

class TestThread implements Runnable/*extendsThread*/{

    //然后重写run()方法

    int tickets = 1000;

    String str = new String("");

    public void run(){

       if(str.equals("method")){

           while(true){

              sale();

           }

       }else{

       while(true){

           synchronized(str){

              if(tickets > 0){

                  try {

                     Thread.sleep(10);

                  } catch (InterruptedException e) {

                     // TODO Auto-generatedcatch block

                     e.printStackTrace();

                  }

                  synchronized (this) {}

              System.out.print("代码:");

              System.out.println("run():"+Thread.currentThread().getName()+"is salling ticket"+tickets--);

                  }

           }

       }

       }

 

    }

    public synchronized void sale(){

       if(tickets > 0){

           try {

              Thread.sleep(10);

           } catch (InterruptedException e) {

              // TODO Auto-generatedcatch block

              e.printStackTrace();

           }

           synchronized (str) {}

           System.out.print("sale():");

           System.out.println("run():"+Thread.currentThread().getName()+"is salling ticket"+tickets--);

           }

    }

}

上例是参数不同导致了死锁…

 

 

 

线程间的通信


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

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

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


Wait(),notify(),notifyAll()都必须放在sysnchronised中,并且必须用sysnchronised中的参数作为三个方法的对象

 

线程要在同一个类写出,方便其他类调用方法,类中变量用private,方法用共有

 

class Producer implements Runnable {

    Q q;

    public Producer(Q q){

       this.q = q;

    }

    @Override

    public void run() {

       int i = 0;

       while(true){

           /*synchronized(q){

              if(q.bFull == true)

                  try {q.wait();} catch (InterruptedException e1){e1.printStackTrace();}

              if(i == 0){

                  q.name = "张三";

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

                  q.sex = "male";

              }else{

                  q.name = "李四";

                  q.sex = "female";

              }

              q.bFull = true;

              q.notify();

           }*/

              if(i == 0)

                  q.put("张三", "male");

              else

                  q.put("李四", "female");

              i = (i+1)%2;        

       }

      

 

    }

 

}

class Coneumer implements Runnable {

    Q q;

    public Coneumer(Q q){

       this.q = q;

    }

    @Override

    public void run() {

       while(true){

           /*synchronized(q){

              if(q.bFull == false)

                  try {q.wait();} catch (InterruptedException e){e.printStackTrace();}

              System.out.print(q.name);

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

              q.bFull = false;

              q.notify();

           }*/

           q.get();

           }

    }

 

}

class Q{

    private boolean bFull = false;

    private String name = "unknown";

    private String sex = "unknown";

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

       if(bFull)

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

       this.name = name;

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

       this.sex = sex;

       bFull = true;

       notify();

    }

    public synchronized void get(){

       if(!bFull)

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

       System.out.print(name);

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

       bFull = false;

       notify();

    }

}

public class ThreadCommunation{

    public static void main(String args[]){

       Q q = new Q();

       new Thread(new Producer(q)).start();

       new Thread(new Coneumer(q)).start();

    }

}

线程生命的控制:


Stop(),suspend(),等方法过时,易导致死锁,不使用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值