zoukankan      html  css  js  c++  java
  • Java笔记3_多线程

    知识:

    1,线程与进程:进程是一个正在执行中的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。线程:就是进程中的一个独立的控制单元。线程在控制着进程的执行。一个进程中至少有一个线程。Java VM启动的时候会有一个进程java.exe,该进程至少一个线程负责java程序的执行,而且这个线程运行的代码存在于main方法中,该线程成为主线程。JVM启动的时候,还要产生一个垃圾回收机制的线程。多线程存在的意义:让程序中的各个部分产生同时的效果,一个进程中多个线程好像同时进行。

    2,创建线程方法1---继承Thread类:(java.lang.Thread)步骤:继承Thread类;复写Thread类中的run方法;调用线程的start方法(该方法的作用:启动线程,调用run方法)多线程程序就相当于多个线程抢资源,因此随机性比较大

    3,创建线程方法2---实现runnable接口:步骤:1,     定义类实现Runnable接口;2, 覆盖Runnable接口中的run方法;3,       通过Thread类建立线程对象;4,     将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数;5,    调用Thread的start方法开启线程并调用Runnable接口子类的run方法

    4,多线程安全问题的原因:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误;解决办法:对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中其他线程不可以参与执行,java提供的解决方式是同步

    5,同步代码块

    Synchronized(对象){

    需要被同步的代码

    对象的参数是一个锁,同步锁,对象如同锁,持有锁的线程可以在同步中执行,没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。

    同步的前提:必须要有两个或者两个以上的线程;必须是多个线程使用同一个锁。

    同步好处:解决了多线程的安全问题;弊端:多个线程需要判断锁,较为消耗资源

    6,同步函数

           同步代码块的同步部分可以直接声明在函数上;而不是放在run上,放在run上就只有Thread0线程运行,而没有另一个线程运行;

           同步函数的锁是this,因为函数被这个所属对象引用。

           同步解决问题的方法:找到同步代码;明确共享数据;明确那部分的代码是操作共享数据的;带sleep测试可以找出程序中的问题

    7,静态同步函数

           静态同步函数的锁是class对象,因为静态没对象,而是通过类直接调用;而且静态进内存是在类加载进之后,对象创建之前;

    8,单例设计模式中懒汉模式的同步处理:

           懒汉式:

           Class Single{

           Private static Single s=null;

           Private Single(){}

    Public staticSingle getInstance(){

                  If(s==null){            //用双重判断的方式减少判断锁的次数,解决低效

                  Synchronized(Single.class)   //静态的锁是当前的class文件

    {     If(s==null){

    S=new Single();

    }

    }

    Return s;

    }

    9,死锁

           同步中的嵌套同步,一直获不到资源

           一个死锁程序:程序中。。。

    10,线程间通信

           多线程之间操作同一个资源,但是操作的动作不同。

           等待唤醒机制:为了满足输出的顺序性,选择使用标记位,进入后进行判断,如果存入,就修改标记位,如果打印,打印之后再修改回去。

    wait,notify,notifyAll:1:wait:让线程等待2:notify:唤醒线程池中的第一个线程3:notifyAll:唤醒线程池中的所有线程

    为什么这些方法定义在了Object类中?1:这些方法存在与同步中。2:使用这些方法时必须要标识所属的同步的锁。3:锁可以是任意对象,所以任意对象调用的方法一定定义Object类中。

    wait(),sleep()有什么区别?wait()可有无参数的调用, 而sleep必须指定睡眠时间,但是有些时候,睡眠时间不好确定,这个时候就可以使用wait.;wait:释放了执行权,释放锁,sleep:释放了执行权,不释放锁;sleep有醒过来的时候,而wait可能醒不了.

    11,生产者消费者

    资源:里面有同步的set和get方法,set是供多个生产者加入,get是让多个消费者得到;

    生产者:实现runnable接口,一个私有的资源,初始化传进一个资源实例,set操作放进复写的run里面。

    消费者:实现runnable接口,一个私有的资源,初始化传进一个资源实例,get操作放进复写的run里面。

    代码参照后面:

    12,停止线程:通过stop方法停止线程.但是这个方法过时,所以不推荐使用;开启多线程,运行代码通常是循环结构,只要控制住循环,就可以run方法结束,也就是线程结束;

    Thread.currentThread().getName():获得当前线程名字;

    在run外部写上修改标记位。run判断不通过就退出了;特殊情况:当线程处于了冻结状态,就不会读取到标记,那么线程就不会结束;当没有指定的方式让冻结的线程恢复到运行状态是,这时需要对冻结进行清除,强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束(Thread里面的方法 interrupt  ------中断线程);

    13,守护线程

    Void setDaemon(Boolean on)  将线程标记为守护线程或用户线程;当正在运行的线程都是守护线程时,JVM退出

    14,join方法

           临时抢夺CPU执行权,用于临时加入线程执行

           特点:当A线程执行到B线程的join方法时,A就会等待,当B线程都执行完,A才会执行。Join可以用来临时加入线程执行

    15,优先级-yield方法

    打印线程时调用toString()方法会按照[线程名称,优先权,线程所在的组名称]输出;默认优先级为5,主线程的优先级就是5;

    Static void    yield() 暂停当前正在执行的线程对象,并执行其他线程

      T1.setPriority(Thread.MAX_PRIORITY).设置成线程的最高优先级10

           优先级越高,运行的概率越高

          

    16,线程的状态以及线程的常用方法:

    线程的状态有就绪状态,运行状态,等待状态,休眠状态,终止状态,当条件齐备的时候就绪状态的线程就会开始执行。

    wait()/notify()/notifyAll(): wait()之后线程释放锁进入等待状态,就绪状态的线程才可以利用锁;进入等待状态的线程只有通过notify()/notifyAll()才能够被唤醒(当条件发生变化)。和synchronized连用。

    sleep(): 不释放琐,只是作一段时间的休眠,休眠完后继续执行。

    yield(): 释放锁,使当前线程马上回到就绪状态,也可能马上在执行。

    17,改进:

    jdk1.5以后将同步和锁封装成了对象进行了优化。

    Lock接口:出现替代了同步代码块或者同步函数。将同步的隐式锁操作变成了显示锁操作。同时更为灵活,可以一个锁上加上多组监视器。

    Condition接口:出现替代了object中的wait  notify  notifyAll方法。将这些监视器方法单独进行了封装,变成Condition监视器对象。可以和任意的锁进行组合。

    将生产者消费者的代码优化。。

    问题:

    1,为什么要覆盖Thread类的run方法呢?Thread类用于描述线程。该类就定义了一个功能,用于存储线程要的代码,该存储功能就是run方法;也就是说,thread类中的run方法,用于存储线程要运行的代码;复写Thread类中的run方法 目的:将自定义的代码存储在run方法,让线程运行。

    2,为什么要将Runnable接口的子类对象传递给Thread的构造函数?

    因为自定义的run方法所属的对象是Runnable接口的子类对象,所以要让线程去指定对象的run方法,就必须明确该run方法所属对象。

    3,实现方式和继承方式有什么区别呢?继承Thread:线程代码存放Thread子类run方法中;实现Runnable,线程代码存放在接口的子类的run方法。实现的方式能避免单线程的局限性,所以建议使用实现接口的方法;Thread本身也实现Runnable接口

    4,什么时候使用多线程?当某些代码同时被执行时,就用单独的线程进行封装,独立运算;多个之间相互不相干的时候封装成多线程。

    程序:

    死锁程序:http://zhidao.baidu.com/question/7744377.html 

     1 class Test implements Runnable
     2 {
     3     private boolean flag;
     4     Test(boolean flag)
     5     {
     6         this.flag = flag;
     7     }
     8 
     9     public void run()
    10     {
    11         if(flag)
    12         {
    13             while(true)
    14             {
    15                 synchronized(MyLock.locka)
    16                 {
    17                     System.out.println(Thread.currentThread().getName()+"...if locka ");
    18                     synchronized(MyLock.lockb)
    19                     {
    20                         System.out.println(Thread.currentThread().getName()+"..if lockb");                    
    21                     }
    22                 }
    23             }
    24         }
    25         else
    26         {
    27             while(true)
    28             {
    29                 synchronized(MyLock.lockb)
    30                 {
    31                     System.out.println(Thread.currentThread().getName()+"..else lockb");
    32                     synchronized(MyLock.locka)
    33                     {
    34                         System.out.println(Thread.currentThread().getName()+".....else locka");
    35                     }
    36                 }
    37             }
    38         }
    39     }
    40 }
    41 
    42 
    43 class MyLock
    44 {
    45     static Object locka = new Object();
    46     static Object lockb = new Object();
    47 }
    48 
    49 class  DeadLockTest
    50 {
    51     public static void main(String[] args) 
    52     {
    53         Thread t1 = new Thread(new Test(true));
    54         Thread t2 = new Thread(new Test(false));
    55         t1.start();
    56         t2.start();
    57     }
    58 }
    59 /*两个锁是相互使用,很容易产生死锁,但也有可能会和谐*/

    生产者消费者程序:

    http://bbs.itheima.com/forum.php?mod=viewthread&tid=33523&page=1#pid195933

     1 /*
     2 生产者,消费者。
     3 多生产者多消费者。 
     4 
     5 if判断标记只有一次,会导致不该运行的线程运行了,会出现数据错误的情况。
     6 while判断标记,解决了线程获取执行权后,是否要运行。
     7 
     8 notify:只能唤醒一个线程,如果唤醒了本方,没有意义。而且while判断标记+notify会导致死锁。
     9 notifyAll 解决了本方线程一定会唤醒对方线程的问题。
    10 
    11 */
    12 class Resource2{
    13         private String name;
    14         private int count = 1;
    15         private boolean flag = false;
    16         public synchronized void set(String name){
    17                 while(flag)
    18                         try{this.wait();}
    19                         catch(InterruptedException e){}
    20                 this.name = name + count;
    21                 count++;
    22                 System.out.println(Thread.currentThread().getName()+"...生产者"+this.name);                
    23                 flag = true;
    24                 notifyAll();
    25         }
    26         public synchronized void get(){
    27                 while(!flag)
    28                         try{this.wait();}
    29                         catch(InterruptedException e){}
    30                 System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name);
    31                 flag = false;
    32                 notifyAll();
    33         }
    34 }
    35 
    36 class Producer implements Runnable{
    37         Resource2 r;
    38         Producer(Resource2 r){
    39                 this.r = r;
    40         }
    41         
    42         public void run(){
    43                 while(true){
    44                         r.set("烤鸭");
    45                 }
    46         }
    47 }
    48 
    49 class Consumer implements Runnable{
    50         
    51         Resource2 r;
    52         Consumer(Resource2 r){
    53                 this.r = r;
    54         }
    55         public void run(){
    56                 while(true){
    57                         r.get();
    58                 }
    59         }
    60 }
    61 
    62 public class ConsumerDemo2 {
    63         public static void main(String[] args) {
    64                 Resource2 r = new Resource2();
    65                 
    66                 Producer pro = new Producer(r);
    67                 Consumer con = new Consumer(r);
    68                 
    69                 Thread t0 = new Thread(pro);
    70                 Thread t1 = new Thread(pro);
    71                 Thread t2 = new Thread(con);
    72                 Thread t3 = new Thread(con);
    73                 
    74                 t0.start();
    75                 t1.start();
    76                 t2.start();
    77                 t3.start();                
    78         }
    79 }

    单例设计模式懒汉式:

     1 /*
     2 单例设计模式。
     3 
     4 
     5 */
     6 //饿汉式。
     7 /*
     8 class Single
     9 {
    10     private static final Single s = new Single();
    11     private Single(){}
    12     public static Single getInstance()
    13     {
    14         return s;
    15     }
    16 }
    17 */
    18 
    19 
    20 //懒汉式
    21 
    22 class Single
    23 {
    24     private static Single s = null;
    25     private Single(){}
    26 
    27 
    28     public static  Single getInstance()
    29     {
    30         if(s==null)
    31         {
    32             synchronized(Single.class)
    33             {
    34                 if(s==null)
    35                     //--->A;
    36                     s = new Single();
    37             }
    38         }
    39         return s;
    40     }
    41 }
    42 
    43 class SingleDemo 
    44 {
    45     public static void main(String[] args) 
    46     {
    47         System.out.println("Hello World!");
    48     }
    49 }

    同步函数例子:

     1 /*
     2 需求:
     3 银行有一个金库。
     4 有两个储户分别存300员,每次存100,存3次。
     5 
     6 目的:该程序是否有安全问题,如果有,如何解决?
     7 
     8 
     9 如何找问题:
    10 1,明确哪些代码是多线程运行代码。
    11 2,明确共享数据。
    12 3,明确多线程运行代码中哪些语句是操作共享数据的。
    13 */
    14 class Bank
    15 {
    16     private int sum;
    17     //Object obj = new Object();
    18     public synchronized void add(int n)
    19     {
    20         //synchronized(obj)
    21         //{
    22             sum = sum + n;
    23             try{Thread.sleep(10);}catch(Exception e){}
    24             System.out.println("sum="+sum);
    25         //}
    26     }
    27 }
    28 class Cus implements Runnable
    29 {
    30     private Bank b = new Bank();
    31     public void run()
    32     {        
    33         for(int x=0; x<3; x++)
    34         {
    35             b.add(100);
    36         }
    37     }
    38 }
    39 class  BankDemo
    40 {
    41     public static void main(String[] args) 
    42     {
    43         Cus c = new Cus();
    44         Thread t1 = new Thread(c);
    45         Thread t2 = new Thread(c);
    46         t1.start();
    47         t2.start();
    48     }
    49 }
  • 相关阅读:
    《Android源码设计模式》--装饰模式
    弹出对话框输入框
    顶部搜索框背景色渐变
    《Android源码设计模式》--模板方法模式
    《Android源码设计模式》--状态模式--责任链模式--解释器模式--命令模式--观察者模式--备忘录模式--迭代器模式
    《Android源码设计模式》--策略模式
    《Android源码设计模式》--抽象工厂模式
    《Android源码设计模式》--工厂方法模式
    《Android源码设计模式》--原型模式
    《Android源码设计模式》--Builder模式
  • 原文地址:https://www.cnblogs.com/yys369/p/2822470.html
Copyright © 2011-2022 走看看