java线程

来源:互联网 发布:淘宝双方已评 不显示 编辑:程序博客网 时间:2024/04/28 02:18

多线程机制

1.线程的基本概念

  1. 线程是一个程序里面不同的执行路径,是一个程序内部的顺序控制流

2.线程和进程的区别:

(1)每一个的进程都有独立的代码和数据空间(进程上下文),进程的切换会有较大的开销

(2)线程可以看成是轻量级的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器【PC】,线程切换的开销小

(3)多进程:在操作系统中能同时运行对个任务(程序)

(4)多线程:在同一应用程序中有多个顺序流同时执行

(5)其中可以看成线程是进程里面的不同的执行路径

(6)进程不是一个可执行的实体

(7)线程从宏观上来说是同时或者并行的,微观上是从CPU的处理上则是分时的。

3.java的线程是通过java.lang.Thread类来实现,(它有一些属性:轻型的实体,独立的调度和分配的基本单位;可以并发执行;共享进程资源)

4.VM启动时会有一个由主方法(public static void main(){})所定义的线程。

5.可以通过创建Thread的实例来创建新的线程

6.每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体

7.通过调用Thread类的start()方法来启动一个线程

2.线程的创建和启动(进程是不能执行的,它是静态的,是个静态的概念,所说的进程执行时指的是主线程的运行)

1.我们现在使用的windows系统是多进程和多线程的执行的

2.cpu运行时比较快,一秒钟执行好几亿次,所以它在执行多个线程时是一个一个加载,并不是先加载一个再加载另一个,把自己的时间分成一个一个小时间片,只有这样,系统才能支持多线程的工作,这只是对单个CPU的计算机而言,要是多个CPU的话就可以实现真正的意义上的同步执行。

3.可以有三种方式创建新的线程:

(1)第一种:定义线程类实现Runnable接口;Thread myThread=new Thread(target)//target为Runnable接口类型;Runnable中只有一个方法:public void run();用以定义线程运行体;使用Runnable接口可以为多个线程提供共享的数据;在实现Runnable接口的类的run方法定义中可以使用Thread的静态方法:public static Thread currntThread()获取当前线程的引用

(2)第二种:可以定义一个Thread的子类并且重写其run方法:

     Class MyThread extends Thread{

   Public void run(){

……..

}

}然后生成该类的对象:

 MyThread ,myThread=new MyThread(…)

线程启动时必须调用Thread这个类并且用到start()方法

3.线程的各个方法

1.在创建一个线程时,只要能从Thread里面接口最好就不要继承,因为继承就不灵活了

2.isAlive()判断线程是否还“活”着,即线程是否还未终止

3.getPriority()获得线程的优先级

4.setPriority()设置线程的优先级

5.Thread.sleep() 将当前线程睡眠指定毫秒数

6.join() 调用某线程的该方法,将当前线程与该线程“合并”,即等待该线程结束,再恢复当前线程的运行

7.yield(),让出CPU,当前线程进入就绪队列等待调度

8.wait()当前线程进入对象的wait pool

9.notify()/notifyAll()唤醒对象的wait pool中的一个/所有等待线程

4.线程的状态控制

1.创建;使用new运算符创建一个线程后,该线程仅仅是一个空对象,此时系统没有分配资源

2就绪;线程处于创建状态时,对其进行start()操作后,系统为该线程分配了除CPU外的所需资源。使它处于可以随时运行的状态

3.运行(阻塞),在运行时占有CPU,可以运行线程的Run()方法。如果某个线程运行时由于某个原因停止,那么就是处于阻塞状态

4.终止 :run()方法执行完后就是终止状态

5.sleep方法:

(1)可以调用Thread的静态方法:public static void sleep(long milis)throws interruptedException使得当前线程休眠(暂时停止执行millis毫秒)

(2)由于是静态的方法,sleep可以由类名直接调用:Thread.sleep(…)

(3)重写的方法不能抛出被重写的方法的异常

6.join方法(合并某个线程)

7.yield方法(让出CPU,给其他线程执行的机会)

  

5.   线程调度和优先级

1.    java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程。线程调度器按照线程的优先级决定应调度哪个线程来执行。

2.    其中线程的优先级用数字来表示,范围从1到10,一个线程的缺省优先级是5

(1)    Thread.MIN_PRIORITY=1;

(2)    Thread.MAX_PRIORITY=10;

(3)    Thread.NORM_PRIORITY=5

3.    使用下述的方法获得或设置线程对象的优先级。

Int getPriority();

Void setPriority(int newPriority);

4.    线程同步(synchronized(this)在线程同步时用于锁定某个线程,不会出现线程同步带来的错误)

(1).在java程序中,引入了对象互斥锁的概念,保证共享数据操作的完整性,每个对象都对应于一个可称为“互斥锁”的标记,这个标记保证在任意时刻,只能有一个线程访问该对象

(2)关键字synchronized来与对象互斥锁联系,当某个对象synchronized修饰时,表明该对象在任意时刻只能由一个线程访问。

(3)其中synchronized还可以放在方法声明中,表示整个方法为同步方法,例如:synchronized public void add(String name){….}

(4)解决线程死锁问题,最好绑定一个对象一个锁,不要绑定多个对象锁定多个锁

(5)解决死锁问题还可将锁的粒度加粗些(执行效率会低一些),就是在锁定一个对象时不要锁一个类对象里面的小对象,可以锁住一个大对象。就是锁定当前整个对象。一般在系统级的程序里面会出现死锁问题.

(6)一般来说我们锁定的对象只是当前的对象,所以在主线程中我们还是可以访问没有被访问的对象的。

(7)最重要的一点是:一般都是主线程执行完后,新线程才执行完,在主线程中调用thread.start()方法启动新线程后并不会等待其run方法返回就继续执行,thread.run方法和原来的主线程是同步并发的运行,并不影响主线程的执行。

(8)其中在加锁的过程中,已经加了锁的对象或者说线程可以随便访问没有上锁的线程。在加锁的过程中部要加太多貌似会使得效率变低。

(9)wait()方法与sleep()方法中,主要区别为:wait()方法执行时,锁synchronized,已经不在这个对象里了,可是在sleep()方法中,锁还是在这个对象的。所以在调用wait()方法中,我们还要执行wait﹢这个线程时,我们要叫醒他,让他继续找到自己的锁来,此时要用到notify()方法来叫醒这个线程,叫醒所有的线程用notifyAll();

(10)如果只让线程wait()而不让notify()提醒,那么这也是一种死锁问题。

(11)Wait时别的线程可以访问锁定对象(调用wait方法的时候必须锁定该对象)sleep时别的线程也不可以访问锁定对象;其中Wait是继承object类,而sleep是继承Thread类