java-多线程篇<上>

1.线程和进程的概念

1.1.进程(Process):拥有独立的内存空间,每个独立执行的程序称为进程
   1.2.线程(Thread):线程是一个程序内部的一条执行路径,Java虚拟机允许应用程序并发地运行多个执行线程
   1.3.线程和进程的区别
           每个进程都有独立的代码和数据空间(进程上下文),进程间的切换开销大
           线程: 同一进程内的线程共享代码和数据空间,线程切换的开销小
           多进程: 在操作系统中能同时运行多个任务(程序)
           多线程: 在同一应用程序中多条执行路径同时执行

2.线程的创建与启动  

第一种:继承Thread类,重写run方法

第二种:实现Runnable接口,重写run方法

3.两种创建方式的比较   
   3.1使用Runnable接口
             还可以从其他类继承;
             保持程序风格的一致性。
   3.2直接继承Thread类
             不能再从其他类继承;
             编写简单,可以直接操纵线程
   使用实现Runnable接口的方式创建线程时可以为相同程序代码的多个线程提供共享的数据。

4.线程小结 
   4.1.Java的线程是通过java.lang.Thread类来实现的。
   4.2.当程序启动运行时,JVM会产生一个线程(主线程),主方法(main方法)就是在这个线程上运行的。
   4.3.可以通过创建Thread的实例来创建新的线程。
         a.每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体。
         b.通过调用Thread类的start()方法来启动一个线程。线程进入Runnable(可运行)状态,它将向线程

调度器注册这个线程。
         c.调用start()方法并不一定马上会执行这个线程,正如上面所说,它只是进入Runnable 而不是

Running。

4.4.每个线程都有一个优先级,一个标识名,多个线程可以同步。没有指定标识名时,会自动为其生成一个

高优先级线程的执行优先于低优先级线程。每个线程都可以或不可以标记为一个守护程序。当某个线程

中运行的代码创建一个新 Thread 对象时,该新线程的初始优先级被设定为创建线程的优先级,并且

当且仅当创建线程是守护线程时,新线程才是守护程序。

4.5.Java虚拟机退出的情况

  • 调用了 Runtime 类的 exit 方法,并且安全管理器允许退出操作发生。
  • 非守护线程的所有线程都已停止运行,无论是通过从对 run 方法的调用中返回,还是通过抛出一个传播到

     run 方法之外的异常

注意,不要直接在程序中调用线程的run()方法。

5.线程的基本使用方法

  • static Thread currentThread ();//返回当前正在执行的线程对象的引用
  • static void yield ();//暂停当前线程一下下。
  • static void sleep (long millis);//线程睡眠(暂停执行)
  • 上面三个都是静态方法,其他的一般不是
  • void start();//使线程启动,进入runnable状态。
  • boolean isAlive();//判断该线程是否处于活动状态
  • boolean isDaemon();//判断是否是守护线程
  • Thread.State getState();//返回该线程的状态
  • void setName(String name);//改变线程名称
  • void setDaemon(boolean on);//true则为守护进程,false为用户进程。

 6.线程的调度 

  1. 线程睡眠: Thread.sleep(long miao);//使线程进入阻塞状态,睡眠结束后进入就绪(Runnable)状态
  2. 线程让步: Thread.yield();//暂停当前执行线程,将执行机会让给同等或更高优先级的线程执行,但是这个时间不能控制.是不确定的.只是让当前线程暂停一下下.
  3. 线程加入: join();//throws InterruptedException 。当前线程调用另一个线程的join方法,则当前线程

转入waiting状态,直到调用join()方法的线程执行完毕,当前线程再由阻塞转为就绪状态。

4.线程等待:Object类中的wait()方法,导致当前线程等待,直到其他线程调用此对象的notify()方法或notifyAll

()方法唤醒该线程。

    5.线程唤醒:Object类的notify()方法,唤醒在。此对象监视器上等待的某个单个线程。选择是随意的。、

Object类的notifyAll()方法,唤醒在此对象监视器上等待的所有线程。

注意:这三个方法(wait,notify,notifyAll)只能在被同步化(synchronized)的方法或代码块中使用。

7.线程停止   

  • 如果run方法中执行的是一个重复执行的循环,可以提供一个标志来控制循环是否执行。
  • 如果线程是因为执行了sleep()方法或wait()方法而进入了阻塞状态,此时想停止它的话可以使用interrupt()方法

程序会抛出InterruptException异常。

  • 如果程序因为输入/输出的等待而阻塞,基本上是必须等待输入/输出的动作完成才能离开阻塞状态。无法通过interrupt

方法使得线程离开run方法,要想离开只能引发一个异常。

7.1 线程的终止

  • 因为run方法的正常退出而自然死亡
  • 因为一个没有捕获的异常终止了run方法而意外死亡

8.线程状态的转换

创建(new)---->[阻塞解除]----->就绪(runnable)---->运行(running)--->[阻塞]---->死亡(dead)

新建状态(new):新创建一个线程对象。

就绪状态(runnable):其他线程调用了该线程的start方法后,该状态的线程位于可运行线程池中,变得可运行,等待

获取cpu使用权。获取了cpu,执行程序代码时也属于就绪状态。

运行状态(running):执行run方法。

阻塞状态(blocked):阻塞状态是因为线程由于某个原因而放弃cpu的使用权,而暂时停止运行,直到线程进入就绪状态

才有机会进入运行状态。阻塞情况有三种:

1.同步阻塞:运行的线程在获取对象的同步锁时,如果该同步锁被其他线程占用,则jvm将它放入锁池中

2.等待阻塞:运行的线程执行wait的方法时,jvm会把该线程放入等待池中。

3.其他阻塞:运行的线程执行sleep()方法或join()方法,或发出I/O请求时,将进入阻塞状态

死亡状态(dead):线程执行完或因异常退出run方法,线程结束生命周期。

注意:调用yield()方法并没有进入阻塞(blocked)状态

9.调整线程的优先级 

Java提供了一个线程调度器来监控程序中启动后进入就绪状态的所有线程。优先级高的线程会获得较多的运行机会

Java线程的优先级用int表示,取值1~10,Thread类的三个静态常量:MAX_PRIORITY=10,MIN_PRIORITY=1

NORM_PRIORITY=5(默认优先级取值为5).

Thread类的setPriority(),getPriority()方法可以设置和获取线程的优先级

注意:优先级高的只是得到cpu的机会概率多一些

10.线程同步(同步锁) 

在Java语言中,引入了对象互斥锁的概念,保证共享数据操作的完整性,每个对象都对应于一个可称为"互斥锁"

的标记,这个标记保证在任何时刻,只能有一个线程访问对象。

关键字synchronized用来与对象互斥锁联系,当某个对象用synchronized修饰时,表明该对象在任何时刻

只能由一个线程访问。

注意:同步锁即synchronized(参数)里的参数必须是引用类型,如成员变量(必须是引用类类型:String)

成员方法(方法的返回值必须是引用类型,不能是int,char),this(即本身对象),this.getClass()//类

11.Synchronized关键字

同步代码块: synchronized(this){需要同步的代码;}

同步方法:public  synchronized void method(){...}

12.死锁问题

有两个线程,x和y,x线程拿到了A对象锁后执行代码,y线程拿到了B对象锁后执行代码,如果这时x线程还要取

B对象锁,而y线程也要取A对象锁,则大家拿着各自的锁不放,就会导致死锁的问题。

解决死锁的办法之一就是:加大锁的粒度。

13.多线程安全问题

当run()方法中的代码操作到了成员变量(共享数据)时,就会出现多线程安全问题(线程不同步问题)

编程技巧:在方法中尽量少操作成员变量,多使用局部变量。

14.容器类的线程安全

大多数的容器类默认都没有考虑线程安全问题,程序必须自行实现同步:

a.用synchronized来锁住这个对象

synchronized (list){  list.add(...) ;}

b.用Collections类的synchronizedXXX()方法返回一个同步化的容器对象

List list=Collections.synchronizedList(new ArrayList());

这种方式在迭代时仍要用synchronized修饰。

List list = Collections.synchronizedList(new ArrayList());...synchronized(list) {Iterator i = list.iterator(); while (i.hasNext()) {foo(i.next());}}

JDK 5.0之后,新增了java.util.concurrent这个包,其中包括了一些确保线程安全的容器类,

如ConcurrentHashMap,CopyOnWriteArrayList,CopyOnWriteArraySet,它们在效率

与安全性上取得了较好的平衡。

总结:

wait():释放cpu执行权,释放锁。

sleep():释放cpu执行权,不释放锁。

JDK1.5版本提供了一些新的对象,优化了等待唤醒机制。

1,将synchronized 替换成了Lock接口。
       将隐式锁,升级成了显示锁。
       Lock 
       获取锁:lock();
       释放锁:unlock();注意:释放的动作一定要执行,所以通常定义在finally中。
       获取Condition对象:newCondition();
   2,将Object中的wait,notify,notifyAll方法都替换成了Condition的await,signal,signalAll。
       和以前不同是:一个同步代码块具备一个锁,该所以具备自己的独立wait和notify方法。
       现在是将wait,notify等方法,封装进一个特有的对象Condition,而一个Lock锁上可以有多个Condition对象。

线程中一些常见方法:
     setDaemon(boolean):将线程标记为后台线程,后台线程和前台线程一样,开启,一样抢执行权运行,
       只有在结束时,有区别,当前台线程都运行结束后,后台线程会自动结束。

join():什么意思?等待该线程结束。当A线程执行到了B的.join方法时,A就会处于冻结状态。
     A什么时候运行呢?当B运行结束后,A就会具备运行资格,继续运行。

加入线程,可以完成对某个线程的临时加入执行。

注意:启动一个jvm时,会有一个前台线程:主线程(执行main方法),还有一个后台线程:垃圾回收机制线程。

时间: 2024-10-11 04:22:16

java-多线程篇<上>的相关文章

黑马程序员-Java多线程篇《四》

                         ------- android培训.java培训.期待与您交流! ---------- 1.线程和进程的概念 1.1.进程(Process):拥有独立的内存空间,每个独立执行的程序称为进程   1.2.线程(Thread):线程是一个程序内部的一条执行路径,Java虚拟机允许应用程序并发地运行多个执行线程   1.3.线程和进程的区别           每个进程都有独立的代码和数据空间(进程上下文),进程间的切换开销大           线程

第12篇-JAVA 多线程

第12篇-JAVA 多线程 每篇一句 :不要只看到艰难,要看艰难后面的胜利 初学心得: 敢于尝试,就等于你已经向成功迈出了第一步 (笔者:JEEP/711)[JAVA笔记 | 时间:2017-04-20| JAVA 多线程 ] 1.进程与线程 1.什么是进程 程序是指令和数据的有序的集合,其本身没有任何运行的含义,是一个静态的概念 进程是一个具有一定独立功能的程序,一个实体 几乎所有的操作系统都支持同时运行多个任务,一个任务通常就是一个程序,每个运行中的程序就是一个进程 当一个程序运行时,内部可

Java总结篇系列:Java多线程(三)

一.一个典型的Java线程安全例子 1 public class ThreadTest { 2 3 public static void main(String[] args) { 4 Account account = new Account("123456", 1000); 5 DrawMoneyRunnable drawMoneyRunnable = new DrawMoneyRunnable(account, 700); 6 Thread myThread1 = new Thr

Java总结篇系列:Java多线程(二)

四.Java多线程的阻塞状态与线程控制 上文已经提到Java阻塞的几种具体类型.下面分别看下引起Java线程阻塞的主要方法. 1.join() join -- 让一个线程等待另一个线程完成才继续执行.如A线程线程执行体中调用B线程的join()方法,则A线程被阻塞,知道B线程执行完为止,A才能得以继续执行. 1 public class ThreadTest { 2 3 public static void main(String[] args) { 4 5 MyRunnable myRunna

带你玩转java多线程系列 “道篇” 多线程的优势及利用util.concurrent包测试单核多核下多线程的效率

java多线程 “道篇” - 多线程的优势及用concurrent包测试单核多核下多线程的效率 1 超哥对于多线程自己的理解 2 测试代码 3 CountDownLatch这个同步辅助类科普 4 如何把电脑设置成单核 5 测试结果 1 超哥对于多线程自己的理解 超哥的理解:对于多线程,无非是对于顺序执行下任务的一种抽取和封装,将原来顺序执行的任务单独拿出来放到线程类的run方法中,通过线程类的start方法进行执行,对于多线程访问共同资源时,我们需要加锁,也就是只有某个线程在拥有锁的时候,才能够

(转)java多线程的一篇好文

云转型基石ThinkServer特性解析 2013-05-29 10:47 佚名 importnew 字号:T | T 本文只是一些针对初学者或者新手的问题,如果你已经具备良好的基础,那么你可以跳过本文,直接尝试针对进阶水平的Java多线程编程问题及解答. AD:WOT2014:用户标签系统与用户数据化运营培训专场 英文原文:java-success.blogspot,编译:王晓杰 如果你即将去一家从事大型系统研发的公司进行Java面试,不可避免的会有多线程相关的问题.下面是一些针对初学者或者新

关于Java多线程的线程同步和线程通信的一些小问题(顺便分享几篇质量高的博文)

Java多线程的线程同步和线程通信的一些小问题(顺便分享几篇质量高的博文) 前言:在学习多线程时,遇到了一些问题,这里我将这些问题都分享出来,同时也分享了几篇其他博客主的博客,并且将我个人的理解也分享给大家. 一.对于线程同步和同步锁的理解(注:分享了三篇高质量的博客) 以下我精心的挑选了几篇博文,分别是关于对线程同步的理解和如何选择线程锁以及了解线程锁的作用范围. <一>线程同步锁的选择 1. 这里我推荐下Java代码质量改进之:同步对象的选择这篇博文. 2. 以上推荐的博文是以卖火车票为例

Java总结篇系列:Java多线程(一)

多线程作为Java中很重要的一个知识点,在此还是有必要总结一下的. 一.线程的生命周期及五种基本状态 关于Java中线程的生命周期,首先看一下下面这张较为经典的图: 上图中基本上囊括了Java中多线程各重要知识点.掌握了上图中的各知识点,Java中的多线程也就基本上掌握了.主要包括: Java线程具有五中基本状态 新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread(); 就绪状态(Runnable):当调用线程对象的start()方法(t

Java多线程系列--“基础篇”01之 基本概念

多线程是Java中不可避免的一个重要主体.从本章开始,我们将展开对多线程的学 习.接下来的内容,是对“JDK中新增JUC包”之前的Java多线程内容的讲解,涉及到的内容包括,Object类中的wait(), notify()等接口:Thread类中的接口:synchronized关键字. 注:JUC包是指,Java.util.concurrent包,它是由Java大师Doug Lea完成并在JDK1.5版本添加到Java中的. 在进入后面章节的学习之前,先对了解一些多线程的相关概念.线程状态图

Java多线程学习篇(三)Lock

Lock 是Java多线程的一个同步机制,用来控制线程对共享资源的访问.线程在执行同步方法或者代码块之前必须先获得一个锁. Lock 的 lock() 和 unlock() 方法; lock():获得一个锁,如果锁不可用,则当前线程将因线程调度目的而被禁用,并在获得锁之前处于休眠状态. unlock():释放掉获得的锁. Lock的作用范围: 若 Lock 是静态的,则作用范围是整个类. public class Test { public static void main(String[] a