java多线程

1. 创建线程有两种方式:

1)扩展java.lang.Thread

public class ThreadTest extends Thread{ }

2)实现Runnable接口

public class ThreadTest implements Runnable{ }

2. Thread类代表线程类,有两个最主要的方法:

1run() 包含线程运行时所执行的代码。

用户的线程类只需要继承Thread类,覆盖Thread类的run()方法即可。在Thread类中的run()方法没有招聘任何异常,所以Thread子类的run()方法也不能声明招聘任何异常。

2start() 用于启动线程。

3.线程的运行过程:

1)主线程与用户自定义的线程并发运行

2)多个线程共享一个对象的实例变量

3)不要随便覆盖Thread类的start()方法,假如一定要覆盖,就在重新定义的start()方法首语句中调用super.start()方法。

4)一个线程只能被启动一次

4.线程的状态转换:

1)新建状态

new语句创建的线程对象处于新建状态,此时它和其他Java对象一样,仅仅在堆区中被分配了内存。

2)就绪状态

当一个线程对象创建后,其他线程调用它的start()方法,该线程就进入就绪状态,JVM会为它创建方法调用栈和程序计数器。处于这个状态的线程位于可运行池中,等待获得CPU的使用权。

3)运行状态

处于这个状态的线程占用CPU,执行程序代码。在并发运行环境中,如果计算机只有一个CPU,那么任何时刻只会有一个线程处于这个状态。如果计算机有多个CPU,那么同一时刻可以让几个线程占用不同的CPU,使它们都处于运行状态。只有牌就绪状态的线程才有机会转到运行状态。

4)阻塞状态

阻塞状态是指线程因为某些原因放弃CPU,暂时停止运行。当线程处于阻塞状态时,JVM不会给线程分配CPU,直到线程重新进入就绪状态,它才有机会转到运行状态。

阻塞状态可分为以下3

1))位于对象等等池中的阻塞状态:当线程牌运行状态时,如果执行了某个对象的wait()方法,JVM就会把线程放到这个对象的等待池中。

2))位于对象锁池中的阻塞状态:当线程牌运行状态,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他线程占用,JVM就会把这个线程放到这个对旬的锁池中。

3))其他阻塞状态:当前线程执行了sleep()方法,或者调用了其他线程的join()方法,或者发出了I/O请求时,就会进入这个状态。

当一个线程执行System.out.println()或者System.in.read()方法时,就会发出一个I/O请求,该线程放弃CPU,进入阻塞状态,直到I/O处理完毕,该线程才会恢复运行。

5)死亡状态

当线程退出run()方法时,就进入死亡状态,该线程结束生命周期。线程有可能是正常执行完run()方法而退出,也有可能是遇到异常而退出。不管线程正常结束还是异常结束,都不会对其他其他线程造成影响。

Thread类的isAlive()方法判断一个线程是否活着,当线程处于死亡状态或者新建状态时,该方法返回false,在其余状态下,该方法返回true.

5.线程的调度:

有两种调度方式:分时调度模型和抢占式调度模型。

分时调度模型是指让所有线程轮流获得CPU的使用权,并且平均分配每个线程占用CPU的时间片。

Java虚拟机采用抢占式高度模型,是指优先让可运行池中优先级高的线程占用CPU,如果可运行池中线程的优先级相同,那么就随机选择一个线程,使其占用CPU。处于运行状态的线程会一直运行,直至它不得不放弃CPU

线程的调度不是跨平台的,它不仅取决于JVM,还依赖于操作系统。

6Thread类的setPriority(int)getPriority()方法分别用来设置优先级和读取优先级。

1MAX_PRIORITY:取值为10,表示最高优先级

2MIN_PRIORITY:取值为1,表示最低优先级

3NORM_PRIORITY:取值为5,表示默认的优先级

如果希望程序能移植到各个操作系统中,应该确保在设置线程的优先级时,只使用MAX_PRIORITYMIN_PRIORITYNORM_PRIORITY这三个优先级。这样才能保证在不同的操作系统中,对同样优先级的线程采用同样的调度方式。

7sleep()方法与yield()方法的区别:

1sleep()方法会给其他线程运行的机会,而不考虑其他线程的优先级,因此会给较低优先级线程一个运行的机会;yield()方法只会给相同优先级或者更高优先级的线程一个运行的机会。

2)当线程执行了sleep()方法后,将转到阻塞状态;当线程执行了yield()方法后,将转到就绪状态。

3sleep()方法声明抛出InterruptedException异常,而yield()方法没有声明招聘任何异常。

4sleep()方法比yield()方法具有更好的可移植性。

8.等待其他线程结束:join()方法

当前运行的线程可以调用另一个线程的join()方法,当前运行的线程将转到阻塞状态,直至另一个线程运行结束,它才会恢复运行(确切的意思是指线程从阻塞状态转到就绪状态)。

9.定时器Timer

Timer timer=new Timer(true);

TimerTask task=new TimerTask(){ }

timer.schedule(task,10,500);//定时器将在10毫秒后开始执行task任务,以后每隔//500毫秒重复执行一次task任务。

timer.schedule(task,10);//只执行一次task任务。

10.同步代码块

为了保证每个线程能正常执行原子操作,Java引入了同步机制,具体做法是在代表原子操作的程序代码前加上synchronized标记,这样的代码被称为同步代码块。

有两种方式加代码锁:

1) 直接在方法前加synchronized标记,

public synchronized void add(){... }

2) 在方法内形成synchronized标记的代码块

public void add(){synchronized(this){... }}

取得对象锁:

1) 假如这个锁已经被其他线程占用,JVM就会把这个消费者线程放到Stack对象的锁池中,消费者线程进入阻塞状态。在Stack对象的锁池中可能会有许多等待锁的线程。等到其他线程释放了锁,JVM会从锁池中随机取出一个线程,使这个线程拥有锁,并且转到就绪状态。

2) 假如这个锁没有被其他线程占用,消费者线程就会获得这把锁,开始执行同步代码块。在一般情况下,消费者线程只有执行完同步代码块,才会释放锁,使得其他线程能够获得锁。

释放对象锁:

1) 执行完同步代码块,就会释放锁。

2) 在执行同步代码块的过程中,遇到异常而导致线程终止,锁也会被释放。

3) 在执行同步代码块的过程中,执行了锁所属对象的wait()方法,这个线程会释放锁,进入对象的等待池。

4) 在执行同步代码块的过程中,执行了锁所属对象的notify()方法后,JVM会从对象的等待池中随机选择一个线程,把它转到对象的锁池中。

线程同步的特征:

1) 如果一个同步代码块和非同步代码块同时操纵共享资源,仍然会造成对共享资源的竞争。因为当一个线程执行一个对象的同步代码块时,其他线程仍然可以执行对象的非同步代码块。

2) 每一个对象都有惟一的同步锁。

3) 在静态方法前面也可以使用synchronized修饰符。

4) 当一个线程开始执行同步代码块时,并不意味着必须以不中断的方式运行。进入同步代码块中的线程也可以执行Thread.sleep()或者执行Thread.yield()方法,此时它并没有释放锁,只是把运行机会(即CPU)让给了其他的线程。

5) synchronized声明不会被继承.

11.死锁:

当一个线程等等由另一个线程持有的锁,而后者正在等待已被第一个线程持有的锁时,就会发生死锁。JVM不监测也不试图避免这种情况,因此保证不发生死锁就成了程序员的责任。

12

 

阅读更多
想对作者说点什么? 我来说一句

Java 5.0多线程编程

2008年12月28日 31KB 下载

Java多线程设计模式上传文件

2009年02月10日 10.8MB 下载

java多线程教程java多线程教程

2011年04月08日 183KB 下载

java多线程java多线程

2009年07月21日 7.37MB 下载

Java 并发性和多线程

2017年12月05日 2.26MB 下载

java 多线程:哲学家思考问题

2009年09月02日 109KB 下载

java多线程教程 java多线程教程

2011年01月15日 97KB 下载

java 总结 web mysql

2017年09月05日 50MB 下载

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭