黑马程序员_源自梦想 线程

来源:互联网 发布:域名怎么解腾讯拦截 编辑:程序博客网 时间:2024/05/16 17:01

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

进程和线程

进程:是一个正在执行中的程序。
每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。
进程的特点:每一个进程都有自己的独立的一块内存空间、一组资源系统。其内部数据和状态都是完全独立的。
怎么看待进程?进程的优点是提高CPU运行效率,在同一时间内执行多个程序,即并发执行。但是从严格上讲,也不是绝对的同一时刻执行多个程序,只不过CPU在执行时通过时间片等调度算法不同进程高速切换。

线程:就是进程中的一个独立的控制单元。(一个线程是进程的一个顺序执行流。)
线程在控制着进程的执行。
线程的特点:同类的多个线程共享一块内存空间和一组系统资源。

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

如何在自定义的代码中,自定义一个线程呢?
        创建线程的第一种方式:继承Thread类。
步骤:
1.定义类继承Thread。
2.复写Thread类中的run方法。
目的:将自定义代码存储在run方法。让线程运行。

3.调用线程的start方法,

  该方法两个作用:启动线程,调用run方法。

class Demo1 extends Thread{public void run(){System.out.println(Thread.currentThread().getName());}}public class ThreadDemo {public static void main(String[] args) {Demo1 d = new Demo1();//创建好一个线程。d.start();//开启线程并执行该线程的run方法。System.out.println("*************************");d.run();//仅仅是对象调用方法。而线程创建了,并没有运行。}}//--------结果------------*************************mainThread-0//main说明d.run()仅仅是对象调用方法。而线程创建了,并没有运行。

创建线程的第二种方式:实现Runnable
1.定义类实现Runnable接口
2.覆盖Runnable接口中的run方法。
将线程要运行的代码存放在该run方法中。
3.通过Thread类建立线程对象。
4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
为什么要将Runnable接口的子类对象传递给Thread的构造函数。
因为,自定义的run方法所属的对象是Runnable接口的子类对象。
所以要让线程去指定指定对象的run方法。就必须明确该run方法所属对象。
5.调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。

class Ext implements Runnable{public void run() {System.out.println("cwk");}}public class RunnableDemo {public static void main(String[] args) {Ext ext = new Ext();Thread t = new Thread(ext);t.start();System.out.println("*********************");new Thread(new Ext()).start();}}
实现方式和继承方式有什么区别呢?
实现方式好处:避免了单继承的局限性。
在定义线程时,建立使用实现方式。
两种方式区别:
继承Thread:线程代码存放Thread子类run方法中。
实现Runnable,线程代码存在接口的子类的run方法。
发现运行结果每一次都不同。
因为多个线程都获取cpu的执行权。cpu执行到谁,谁就运行。明确一点,在某一个时刻,只能有一个程序在运行。(多核除外)
cpu在做着快速的切换,以达到看上去是同时运行的效果。我们可以形象把多线程的运行行为在互相抢夺cpu的执行权。
这就是多线程的一个特性:随机性。谁抢到谁执行,至于执行多长,cpu说的算。

线程五状态:创建、运行、阻塞、挂起、死亡(java编程思想中4状态 创建、运行、阻塞、死亡)

1.创建状态(new Thread())
2.运行状态(start())
3.阻塞状态(pend)

(1)通过调用sleep()方法使线程进入休眠状态,线程在指定时间内不会运行。
        (2)通过调用join()方法使线程挂起,使自己等待另一个线程的结果,直到另一个线程执行完毕为止。
4.挂起状态(suspend)
 挂起实际上是让线程进入“非可执行”状态下,在这个状态下CPU不会分给线程时间片,进入这个状态可以用来暂停一个线程的运行;在线程挂起后,可以通过重新唤醒线程来使之恢复运行。
     (1)通过调用wait()方法使线程挂起,直到线程得到了notify()和notifyAll()消息,线程才会进入“可执行”状态。
     (2)使用suspend挂起线程后,可以通过resume方法唤醒线程。(不使用)
虽然suspend和resume可以很方便地使线程挂起和唤醒,但由于使用这两个方法可能会造成死锁,因此,这两个方法被标识为 deprecated(抗议)标记,这表明在以后的jdk版本中这两个方法可能被删除,所以尽量不要使用这两个方法来操作线程。
      调用sleep()、yield()、suspend()的时候并没有被释放锁
      调用wait()的时候释放当前对象的锁

      wait()方法表示,放弃当前对资源的占有权,一直等到有线程通知,才会运行后面的代码。
      notify()方法表示,当前的线程已经放弃对资源的占有,通知等待的线程来获得对资源的占有权,但是只有一个线程能够从wait状态中恢复,然后继续运行wait()后面的语句。
      notifyAll()方法表示,当前的线程已经放弃对资源的占有,通知所有的等待线程从wait()方法后的语句开始运行。 

阻塞与挂起的区别:(以前没这个概念,网上引用)
理解一:挂起是一种主动行为,因此恢复也应该要主动完成,而阻塞则是一种被动行为,是在等待事件或资源时任务的表现,你不知道他什么时候被阻塞(pend),也就不能确切 的知道他什么时候恢复阻塞。而且挂起队列在操作系统里可以看成一个,而阻塞队列则是不同的事件或资源(如信号量)就有自己的队列。
理解二:阻塞(pend)就是任务释放CPU,其他任务可以运行,一般在等待某种资源或信号量的时候出现。挂起(suspend)不释放CPU,如果任务优先级高就永远轮不到其他任务运行,一般挂起用于程序调试中的条件中断,当出现某个条件的情况下挂起,然后进行单步调试。
理解三:pend是task主动去等一个事件,或消息.suspend是直接悬挂task,以后这个task和你没任何关系,任何task间的通信或者同步都和这个suspended task没任何关系了,除非你resume task;
理解四:任务调度是操作系统来实现的,任务调度时,直接忽略挂起状态的任务,但是会顾及处于pend下的任务,当pend下的任务等待的资源就绪后,就可以转为ready了。ready只需要等待CPU时间,当然,任务调度也占用开销,但是不大,可以忽略。可以这样理解,只要是挂起状态,操作系统就不在管理这个任务了。
理解五:挂起是主动的,一般需要用挂起函数进行操作,若没有resume的动作,则此任务一直不会ready。而阻塞是因为资源被其他任务抢占而处于休眠态。两者的表现方式都是从就绪态里“清掉”,即对应标志位清零,只不过实现方式不一样。

5.死亡状态
多线程问题
     问题的原因:

当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,
另一个线程参与进来执行。导致共享数据的错误。
     解决办法:
对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。
多线程的同步依靠的是对象锁机制,synchronized关键字的背后就是利用了封锁来实现对共享资源的互斥访问。

//用synchronized进行加锁class Ticket implements Runnable{private  int tick = 200;public synchronized void show()//this{try{Thread.sleep(30);}catch(Exception e){}System.out.println(Thread.currentThread().getName()+"....show.... : "+ tick--);}public void run() {for(int i = 0; i < 100; i++)show();}}public class  ThisLockDemo{public static void main(String[] args) {Ticket t = new Ticket();Thread t1 = new Thread(t);Thread t2 = new Thread(t);t1.start();t2.start();}}

//同一对象用this进行加锁class Ticket implements Runnable{private  int tick = 200; //private Object obj  = new Object();public  void show(){try{Thread.sleep(30);}catch(Exception e){}System.out.println(Thread.currentThread().getName()+"....show.... : "+ tick--);}public void run() {//synchronized (obj) {synchronized (this) {for(int i = 0; i < 100; i++)show();}}}

//静态加锁的是类本身 Ticket.classclass Ticket implements Runnable{private static  int tick = 200; //private Object obj  = new Object();public static synchronized  void show()//静态加锁的是类本身Ticket.class{try{Thread.sleep(30);}catch(Exception e){}System.out.println(Thread.currentThread().getName()+"....show.... : "+ tick--);}public void run() {//synchronized(Ticket.class){}        for(int i = 0; i < 100; i++)     show();}}

//死锁(一个先给钱,才能取货;另一个你先给货,才能拿钱;相互僵持着)package com.cwk.inner;class Test implements Runnable{private int i ;public Test(int i){this.i = i;}public void run() {if(i == 1){while(true){synchronized(DB.one){System.out.println(Thread.currentThread().getName() + "-->one");synchronized (DB.two) {System.out.println(Thread.currentThread().getName() + "-->two");}}}}else{while(true){synchronized(DB.two){System.out.println(Thread.currentThread().getName() + "-->two");synchronized (DB.one) {System.out.println(Thread.currentThread().getName() + "-->one");}}}}}}class DB{public static Object one = new Object();public static Object two = new Object();}class  DeadLockTest{public static void main(String[] args) {Thread t1 = new Thread(new Test(1));Thread t2 = new Thread(new Test(0));t1.start();t2.start();}}


原创粉丝点击