zoukankan      html  css  js  c++  java
  • 黑马程序员——java学习6(127-151)——多线程

    1、多线程

    进程:是一个正在执行中的程序。

      每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫控制单元。

    线程:就是进程中的一个独立的控制单元

      线程在控制着进程的执行

    一个进程中至少有一个线程。

    Java VM 启动的时候回有一个进程java.exe

    该进程中至少一个线程负责java程序的执行

    而且这个线程运行的代码存在于main方法中

    该线程称之为主线程。

    扩展:其实更细节说明jvm,启动的还有垃圾回收机制的线程

     创建线程的方式

    1.1继承Thread

    (1)定义类,继承Thread

    (2)覆写Thread类中的run方法

      目的:将自定义的代码存储在run方法中,让线程运行。

    (3)调用线程的start方法,

       作用:启动线程,调用run方法.

    多线程的随机性:每次运行结果不同,单核CPU在某一个时刻只能执行一个程序,cpu在快速切换,以达到看上去同时运行的效果。

    1.1.1为何覆盖run方法?

    Thread用于描述线程,该类就定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法。

    即run用于存储线程要运行的代码。

     1 class Demo extends Thread{
     2     public void run(){
     3         for(int x=0;x<60;x++)
     4         {
     5             System.out.println("demo run---"+x);
     6         }
     7     };
     8 }
     9 public class ThreadDemo {
    10     public static void main(String[] args) {
    11         Demo d=new Demo();
    12         //d.start();//开启线程并执行该线程的run方法,demorun与helloworld相互执行
    13         d.run();//仅仅是对象调用方法,而线程创建了,并没有运行,demorun全部执行完才执行helloworld
    14         for(int x=0;x<60;x++)
    15         {
    16             System.out.println("Helloworld---"+x);
    17         }
    18 }
    19 }

    1.1.2、线程方法

    static Thread currentThread();获取当前线程对象,静态的,调用时为Thread.currentThread();

    getName();获取线程名称

    设置线程名称:setName();或者构造函数

    1.2、创建线程的第二种方法(常用)

    (1)定义类实现Runnable接口

    (2)覆盖Runnable接口中的run方法

      将线程要运行的代码存放在该run方法中

    (3)通过Thread类建立线程对象

    (4)将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数

      为何将Runnable接口的子类对象传递

      因为自定义的run方法所述的对象是Runnable接口的子类对象

      所以要让线程去执行指定对象的run方法,就必须明确该run所属对象

    (5)调用Thread类的start方法开启线程并调用Runnable接口子类的run方法

    好处:避免单继承的局限性

    区别:

    继承Runnable:线程代码存放在Thread子类的run方法中,无父类时用

    实现Runnable:线程代码存在接口的子类的run方法中,避免局限

     1 /*
     2  * 需求:
     3  * 银行有一个金库
     4  * 有两个储户分别存300元,每次存100,分3次
     5  * 
     6  * 目的:该程序是否有安全问题,如果有,如何解决?
     7  * 
     8  * 如何找问题
     9  * 1、明确哪些代码是多线程运行代码
    10  * 2、明确共享数据
    11  * 3、明确多线程运行代码中哪些语句是操作共享数据的
    12  * */
    13 
    14 package learn;
    15 class Bank
    16 {
    17     private int sum;
    18     public void add(int n)
    19     {
    20         sum=sum+n;
    21         try{Thread.sleep(10);}catch(Exception e){}
    22         System.out.println("sum"+sum);
    23     }
    24 }
    25 class Cus implements Runnable
    26 {
    27     private Bank b=new Bank();
    28     public void run()
    29     {
    30         for(int x=0;x<3;x++)
    31         {
    32             b.add(100);
    33         }
    34     }
    35 }
    36 public class BankDemo {
    37     public static void main(String[] args) {
    38         Cus c=new Cus();
    39         Thread t1=new Thread(c);
    40         Thread t2=new Thread(c);
    41         t1.start();
    42         t2.start();
    43     }
    44 }

    1.3、安全问题

    当多条语句操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,

    另一个线程参与执行,导致共享数据的错误

    解决办法:

      对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中其他线程不可参与执行

    同步代码块。

    synchronized(对象)

    {

      需要被同步的代码  

    }

    例:火车上的厕所

    同步的前提:

    (1)必须有两个或以上的线程

    (2)必须多个线程使用同一个锁

    PS:必须保证同步中只有一个线程在执行

    好处:解决了多线程的安全问题

    弊端:判断锁,消耗资源

    同步的方式:

    (1)同步代码块,使用的锁是obj

    (2)同步函数(作修饰符加入),使用的锁是this

    (3)静态方法用过的锁是class,即该方法所在类的字节码文件对象,函数列表中写作(类名.class)

    1.4、单例

     1 package learn;
     2 /*
     3  * class Single
     4  * {
     5  *     private static final Single s=new Single();
     6  *  private Single(){};
     7  *  public static Single getInstance()
     8  *  {
     9  *      return s;
    10  *  }
    11  * }
    12  * */延迟加载的单例模式示例
    13 class Single
    14 {
    15     private static Single s=null;
    16     private Single(){}
    17     public static Single getInstance(){
    18         if(s==null)
    19             synchronized(Single.class){
    20                 if(s==null)
    21                     s=new Single();
    22             }
    23         return s;
    24     }
    25 }
    26 public class SingleDemo {
    27 
    28 }

    1.5、死锁

    同步中嵌套同步

     1 package learn;
     2 class Test implements Runnable
     3 {
     4     private boolean flag;
     5     Test(boolean flag)
     6     {
     7         this.flag=flag;
     8     }
     9     public void run(){
    10         if(flag)
    11         {
    12             synchronized(MyLock.locka)
    13             {
    14                 System.out.println("if locka ");
    15                 synchronized(MyLock.lockb)
    16                 {
    17                     System.out.println("if lockb");
    18                 }
    19             }
    20         }
    21         else
    22         {
    23             synchronized(MyLock.lockb)
    24             {
    25                 System.out.println("else lockb");
    26                 synchronized(MyLock.locka)
    27                 {
    28                     System.out.println("else locka");
    29                 }
    30             }
    31         }
    32     }
    33 }
    34 
    35 class MyLock{
    36     static Object locka=new Object();
    37     static Object lockb=new Object();
    38 }
    39 public class DeadLockTicket {
    40     public static void main(String[] args) {
    41         Thread t1=new Thread(new Test(true));
    42         Thread t2=new Thread(new Test(false));
    43         t1.start();
    44         t2.start();
    45     }
    46 }

    1.6、线程间通信

    1.6.1等待唤醒机制

    wait都存放在线程池,notify通常唤醒第一个被等待的,notifyall唤醒全部,三者都必须用在同步中(因须有锁),也需加前缀obj.wait

    只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒

    而锁是任意对象,所以可以被任意对象调用的方法定义在object类中

     1 package learn;
     2 class Res{
     3     private String name;
     4     private String sex;
     5     private boolean flag=false;
     6     public synchronized void set(String name,String sex)
     7     {
     8         if(flag)
     9             try{this.wait();}catch(Exception e){}
    10         this.name=name;
    11         this.sex=sex;
    12         flag=true;
    13         this.notify();
    14     }
    15     public synchronized void out()
    16     {
    17         if(!flag)
    18             try{this.wait();}catch(Exception e){}
    19         System.out.println(name+"..."+sex);
    20         flag=false;
    21         this.notify();
    22     }
    23 }
    24 
    25 class Input implements Runnable{
    26     private Res r;
    27     Input(Res r)
    28     {
    29         this.r=r;
    30     }
    31     public void run()
    32     {
    33         int x=0;
    34         while(true)
    35         {
    36             if(x==0)        
    37                 r.set("mike", "nan");            
    38             else            
    39                 r.set("lili", "nv");
    40             x=(x+1)%2; 
    41         }
    42     }
    43 
    44 }
    45 
    46 class Output implements Runnable{
    47     private Res r;
    48     Output(Res r)
    49     {
    50         this.r=r;
    51     } 
    52     public void run()
    53     {
    54         int x=0;
    55         while(true)
    56         {
    57             r.out();
    58         }
    59     }
    60 }
    61 public class InputOutputDemo {
    62     public static void main(String[] args) {
    63         Res r=new Res();
    64         //匿名对象
    65         new Thread(new Input(r)).start();
    66         new Thread(new Output(r)).start();
    67         
    68 //        Input in=new Input(r);
    69 //        Output out =new Output(r);
    70 //        Thread t1=new Thread(in);
    71 //        Thread t2=new Thread(out);
    72 //        t1.start();
    73 //        t2.start();
    74     }
    75 }

    1.6.2、生产者消费者例子

    多个生产者,多个消费者,while循环判断标记,notifyAll

     1 package pack;
     2 class Resource{
     3     private String name;
     4     private int count=1;
     5     private boolean flag=false;
     6     
     7     public  synchronized void set(String name)
     8     {
     9         while(flag)
    10             try{wait();}catch(Exception e){}
    11         this.name=name+"..."+count++;
    12         System.out.println(Thread.currentThread().getName()+"生产者"+this.name);
    13         flag=true;
    14         this.notifyAll();
    15     }
    16     public synchronized void out(){
    17         while(!flag)
    18             try{wait();}catch(Exception e){}
    19         System.out.println(Thread.currentThread().getName()+"消费者............"+this.name);
    20         flag=false;
    21         this.notifyAll();
    22     }
    23 }
    24 
    25 class Producer implements Runnable{
    26     private Resource res;
    27     Producer(Resource res){
    28         this.res=res;
    29     }
    30     public void run(){
    31         while(true)
    32         {
    33             res.set("+商品+");
    34         }
    35     }
    36 }
    37 
    38 class Consumer implements Runnable{
    39     private Resource res;
    40     Consumer(Resource res){
    41         this.res=res;
    42     }
    43     public void run(){
    44         while(true)
    45         {
    46             res.out();
    47         }
    48     }
    49 }
    50 public class ProduceConsumerDemo {
    51     public static void main(String[] args) {
    52         Resource r=new Resource();
    53         Producer pro=new Producer(r);
    54         Consumer con=new Consumer(r);
    55         
    56         Thread t1=new Thread(pro);
    57         Thread t2=new Thread(pro);
    58         Thread t3=new Thread(con);
    59         Thread t4=new Thread(con);
    60         t1.start();
    61         t2.start();
    62         t3.start();
    63         t4.start();
    64     }
    65 }

    1.6.3、多线程升级锁Lock

    JDK1.5中提供了多线程升级解决方案

    将同步syn替换成现实Lock操作

    将Object中的wait,notify,notifyAll,替换了Condition对象

    该对象可以Lock锁,进行获取

    实现了本方只唤醒对方操作

     1 package learn;
     2 
     3 import java.util.concurrent.locks.Condition;
     4 import java.util.concurrent.locks.Lock;
     5 import java.util.concurrent.locks.ReentrantLock;
     6 
     7 class Resource{
     8     private String name;
     9     private int count=1;
    10     private boolean flag=false;
    11     private Lock lock=new ReentrantLock();
    12     private Condition condition_pro=lock.newCondition();
    13     private Condition condition_con=lock.newCondition();
    14     public  void set(String name)throws InterruptedException
    15     {
    16         lock.lock();
    17         try{    
    18             while(flag)
    19             condition_pro.await();
    20             this.name=name+"..."+count++;
    21             System.out.println(Thread.currentThread().getName()+"生产者"+this.name);
    22             flag=true;    
    23             condition_con.signal();
    24         }
    25         finally{
    26             lock.unlock();
    27         }
    28         
    29     }
    30     public void out()throws InterruptedException{
    31         lock.lock();
    32         try{
    33         while(!flag)
    34             condition_con.await();
    35         System.out.println(Thread.currentThread().getName()+"消费者............"+this.name);
    36         flag=false;
    37         condition_pro.signal();
    38         }
    39         
    40         finally
    41         {
    42             lock.unlock();
    43         }
    44     }
    45 }
    46 
    47 class Producer implements Runnable{
    48     private Resource res;
    49     Producer(Resource res){
    50         this.res=res;
    51     }
    52     public void run(){
    53         try{
    54         while(true)
    55         {
    56             res.set("+商品+");
    57         }
    58         }
    59         catch(Exception e)
    60         {}
    61     }
    62 }
    63 
    64 class Consumer implements Runnable{
    65     private Resource res;
    66     Consumer(Resource res){
    67         this.res=res;
    68     }
    69     public void run(){
    70         while(true)
    71         {
    72             try{
    73             res.out();
    74             }
    75             catch(Exception e)
    76             {}
    77         }
    78     }
    79 }
    80 public class ProducerConsumerDemo2 {
    81     public static void main(String[] args) {
    82         Resource r=new Resource();
    83         Producer pro=new Producer(r);
    84         Consumer con=new Consumer(r);
    85         
    86         Thread t1=new Thread(pro);
    87         Thread t2=new Thread(pro);
    88         Thread t3=new Thread(con);
    89         Thread t4=new Thread(con);
    90         t1.start();
    91         t2.start();
    92         t3.start();
    93         t4.start();
    94     }
    95 }

    1.7、如何停止线程?

    stop方法已过时,只能让run方法结束,即控制run中的循环结束

    特殊情况:

    当线程处于冻结状态

    就不会读取到标记,那么线程就不会结束

    当没有指定的方式让冻结的线程回复到运行状态时,这时需要对冻结进行清除

    强制让线程回复到运行状态中来,这样就可以操作标记让线程结束

    interrput();方法

    1.8、守护线程

    1.9、join

    当A线程执行到B线程的join方法时,A就会等到B执行完再执行

     1 package pack;
     2 class Demo implements Runnable
     3 {
     4     public void run(){
     5         for(int x=0;x<70;x++)
     6             System.out.println(Thread.currentThread().getName()+"..."+x);
     7     }
     8 }
     9 public class JoinDemo {
    10  public static void main(String[] args) throws InterruptedException {
    11     Demo d=new Demo();
    12     Thread t1=new Thread(d);
    13     Thread t2=new Thread(d);
    14     t1.start();
    15     //t1抢夺CPU执行权
    16     t1.join();
    17     t2.start();
    18     
    19     for(int x=0;x<80;x++)
    20     {
    21         System.out.println("main..."+x);
    22     }
    23     System.out.println("over");
    24 }
    25 }

    1.9.1、线程优先级

    所有线程默认优先级5,一共1-10级

    1.9.2、yield();

    尽量轮流执行

    1.9.3、开发举例

     1 package pack;
     2 
     3 public class ThreadTest {
     4     public static void main(String[] args) {
     5         //匿名内部类更方便
     6         new Thread()
     7         {
     8             public void run()
     9             {
    10                 for(int x=0;x<100;x++)
    11                 {
    12                     System.out.println(Thread.currentThread().getName()+"..."+x);
    13                 }
    14             }
    15         }.start();
    16         
    17         for(int x=0;x<100;x++)
    18         {
    19             System.out.println(Thread.currentThread().getName()+"..."+x);
    20         }
    21             
    22         
    23         Runnable r=new Runnable(){
    24             public void run(){
    25                 for(int x=0;x<100;x++)
    26                 {
    27                     System.out.println(Thread.currentThread().getName()+"..."+x);
    28                 }
    29                 
    30             }    
    31         };
    32         new Thread(r).start();
    33     }
    34 }
    35 
    36 //麻烦
    37 //class Test1 extends Thread
    38 //{
    39 //    public void run()
    40 //    {
    41 //        for(int x=0;x<100;x++)
    42 //            System.out.println(Thread.currentThread().getName());
    43 //    }
    44 //}
  • 相关阅读:
    与众不同 windows phone (50)
    与众不同 windows phone (49)
    重新想象 Windows 8.1 Store Apps (93)
    重新想象 Windows 8.1 Store Apps 系列文章索引
    重新想象 Windows 8.1 Store Apps (92)
    重新想象 Windows 8.1 Store Apps (91)
    重新想象 Windows 8.1 Store Apps (90)
    重新想象 Windows 8.1 Store Apps (89)
    重新想象 Windows 8.1 Store Apps (88)
    重新想象 Windows 8.1 Store Apps (87)
  • 原文地址:https://www.cnblogs.com/sunxlfree1206/p/4679111.html
Copyright © 2011-2022 走看看