多线程学习总结一

来源:互联网 发布:unity3d ulua 教程 编辑:程序博客网 时间:2024/05/20 10:55

线程是进程中的内容,一个进程中至少有一个线程。
进程:
是一个正在执行中的程序。每一个进程执行都有一个执行顺序,该顺序就是一个执行路径。

线程:
就是进程中的一个独立的控制单元。线程在控制着进程的执行。

 如何在自定义代码中,自定义一个线程?
通过对api的查找java 已经提供了对线程这类事物的描述,就Thread类。
创建线程的第一种方式:继承Thread类
步骤:
1,定义类继承Thread.
2,复写Thread类中的run方法。
3,调用线程的start方法

为什么要覆盖Thread中的run方法呢?
Thread类用于描述线程.
该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法。
说白了就是定义了一个线程,所要让线程实现的代码都需要写在run方法之中


创建线程的第二种方式:实现Runable接口
步骤:
--------------------------------------------------------------
1,定义类实现Runnable接口

2,覆盖Runnable接口重的run方法
将线程要运行的代码存放该run方法中。

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

4,将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
为什么要将Runnable接口的子类对象传递给Thread的构造函数.
因此,自定义run方法所属的对象是Runnable接口的子类对象。
所以要让线程去执行指定对象的run 方法,就必须明确该run方法所属对象。

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

实现方式和继承方式有什么区别?
实现方式好处,避免了但继承的局限性。
在定义线程时,建议使用实现方式。

继承Thread:线程代码存放在Thread子类run方法中。
实现Runnable:线程代码存放在接口的子类run方法中。
---------------------------------------------------------------


所谓死锁: 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。 由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象死锁。

 


(转)整体概念:
1,什么是进程?
一个程序对应一个应用程序,例如在WINDOWS操作系统启动WORD就表示启动了一个进程。在JAVA的开发环境下启动JVM,就表示启动了一个进程。现代的计算机都是支持多进程的,在同一个操作系统中,可以同时启动多个进程。
2,多进程有什么作用?
单进程计算机只能做一件事情。
玩电脑,一边玩游戏(游戏进程)一边听音乐(音乐进程)。
对于单核计算机来讲,在同一个时间点上,游戏进程和音乐进程是同时在运行的吗?不是,因为计算机的CPU只能在某个时间点上做一件事,由于计算机在“游戏进程”和“音乐进程”之间频繁的切换执行,切换速度极高,人类感觉游戏和音乐在同时进行。
多进程的作用不是提高执行速度,而是提高CPU的使用率。
进程和进程之间内存是独立的。
3,什么是线程?
线程是一个进程中的执行场景,一个进程可以启动多个线程。
4,多线程有什么作用?
多线程不是为了提高执行速度,而是提高应用程序的使用率。

比喻下,两个进程所需要条件都一样,A进程只有一个a线程去执行耗费cpu资源为10%,而B进程中有b、c线程去执行,可以把cpu的资源耗费提高为20%左右。相较下B线程的执行速度就要快一些了,当然没有考虑内存大小的因素,当然cpu的频率也够快。


多线程的五种状态
        
被创建--运行--临时状态也称阻塞状态(具备执行资格,但没有执行权。等待切换被执行,)---冻结(放弃了执行资格) ---消亡(线程彻底死亡)


如果解决卖票多线程卖同一张票。
可以将票数设置为static,只生成一次。这样就不会每次生成一个线程就会出现一个新的票数了,详细请查看static用法。

通过分析,发现打印出0,-1,-2等错票。
多线程运行出现了安全问题。
问题原因:
    当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没执行完,另一个线程参与进来执行,导致共享数据的错误。
解决办法:
  对于多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行。

JAVA对于多线程的安全问题提供了专业的解决方式。
就是同步代码块。

sysnchronized(对象)
{
需要被同步的代码
}
例如:
sysnchronized(obj)
{
}


老师分析与讲解:
如果同步函数被静态化修饰后,使用的锁是什么呢?
通过验证发现不在是this,因为静态方法中也不可以定义this.

静态进内存是,内存中没有本类对象,但是一定有该类对应的字节码文件对象。
类名.class 该对象的类型是Class//可以用get.class来获取某一对象的实例。字节码实例

静态的同步方法:使用的锁是该方法所在类的字节码文件对象。类名.class


※单例设计模式:
//饿汉式
class Single
{
  private static final Single s = new Single();
  private Single(){}
  public static Single getInstance()
  {
      return s;
  }
}

//懒汉式  //为了实例的延迟加载,如果多线程访问时会出现安全问题。可以用同步来解决。不过有些低效。用双重判断可以解决低效。

class Single {
  private static Single s = null;
  private Single(){}
  public static Single getInstance()
  {
       if(s==null)
          s = new Single();
       return s;
  }
}


解决低效率代码://延迟加载的单例设计模式示例标准规范。
class Single {
  private static Single s = null;
  private Single(){}
  public static Single getInstance()
  {
       if(s==null) //只判断一次将不在进来判断同步代码,加同步的时候使用的锁是该类所属的字节码文件对象。
     {

      synchronized(Sing.class) // 因为在静态方法中是无法使用this锁,所以只能使用该类所属的字节码文件对象(Sing.class)来作为锁。
       if(s==null)
          s = new Single();
       return s;
      }
  }
}

懒汉式和饿汉式区别:
饿汉式:
         public class Singleton{
             private static Singleton singleton = new Singleton ();
             private Singleton (){}
             public Singleton getInstance(){return singletion;}
        }
 
     懒汉式:
        public class Singleton{  //懒汉式在操作延迟加载时如果不加上synchronized会出现安全问题,懒汉式是一种延迟对象的加载。
             private static Singleton singleton = null;
             public static synchronized synchronized getInstance(){
                  if(singleton==null){
                      singleton = new Singleton();
                  }
                 return singleton;
             }
        }
 
     比较:
饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变
懒汉式如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的,懒汉式如果加上synchronized会导致低效。可以使用双重if语句判断来避免每次运行synchronized造成的低效。
          
推荐使用第一种

 

死锁:
死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。   导致死锁的根源在于不适当地运用“synchronized”关键词来管理线程对特定对象的访问。“synchronized”关键词的作用是,确保在某个时刻只有一个线程被允许执行特定的代码块,因此,被允许执行的线程首先必须拥有对变量或对象的排他性的访问权。当线程访问对象时,线程会给对象加锁,而这个锁导致其它也想访问同一对象的线程被阻塞,直至第一个线程释放它加在对象上的锁。

一般死锁发生在同步嵌套同步中。


 

原创粉丝点击