Java多线程
理解进程和线程
通俗的解释
一个系统运行着很多进程,可以比喻为一条马路上有很多马车
不同的进程可以理解为不同的马车
而同一辆马车可以有很多匹马来拉----这些马就是线程
假设道路的宽度恰好可以通过一辆马车
道路可以认为是临界资源
那么马车成为分配资源的最小单位(进程)
而同一个马车被很多匹马驱动(线程)----即最小的运行单位
每辆马车马匹数>=1
所以马匹数=1的时候进程和线程没有严格界限,只存在一个概念上的区分度
马匹数>1的时候才可以严格区分进程和线程
专业的解释
简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
线程的划分尺度小于进程,使得多线程程序的并发性高。另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.
java中实现多线程有两种方法
1 继承Thread类 2 实现Runnable接口。
用Thread类创建线程
1 要将一段代码在一个新的线程上运行,该代码应该在一个类的run函数中,并且run函数所在的类是
Thread类的子类。倒过来看:我们要实现多线程,必须编写一个继承了Thread类的子类,子类覆盖了
Thread的run()函数,在子类的函数中调用想在新线程上运行的程序代码。
2 启动一个新的线程我们不是直接调用Thread的子类的run()方法,而是调用Thread子类对象的start方
法,start()方法将产生一个新的线程,并在该线程上运行该Thread类对象中的run()方法,根据面向对象
的运行时的多态性,在该线程上实际运行的是Thread子类对象的run()方法。
3由于线程的代码段在run方法中,那么该方法执行完成以后线程也就相应的结束了,因而我们可以通过
控制run方法中的循环条件来控制线程的结束。
class 类名 extends Thread
{
.......
public void run()
{
覆写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 类名 implements Runnable
{
........
public void run()
{
覆写run方法
}
}
实现Runnable接口比继承Thread类所具有的优势:
1):适合多个相同的程序代码的线程去处理同一个资源
2):可以避免java中的单继承的限制
3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。
进程的同步与死锁
同步可以采用 同步代码块和同步函数2中方法完成
同步代码块:
synchronized(同步对象)
{
//需要同步的代码
}
同步函数:
synchronized 方法返回类型 方法名(参数列表)
{
//代码
}
//非静态同步函数使用 this 做为同步对象(同步函数所属对象的引用)
//静态同步函数使用 类名.class 做为同步对象(所属类的字节码文件对象)
线程通信
多个线程共享一段数据,但是对数据的操作不同
等待唤醒机制:wait(); notify(); notifyAll()
线程间的通信
1 wait: 告诉当前线程放弃监视器并进入睡眠状态直到其它线程进入同一监视器并调用notify为止
2 notofy: 唤醒同一对象监视器中调用wait的第一个线程。
3 notifyAll: 唤醒同一对象监视器中调用wait的所有线程,具有最高优先级的线程首先被唤醒并执行。
public class Q {
private String name="unknown";
private String sex="unknown";
boolean inFull=false;
public synchronized void put(String name,String sex)
{
if(inFull){
try {
wait();
} catch (Exception e) {
e.printStackTrace();
} }
this.name=name;
this.sex=sex;
inFull=true;
notify();
}
public synchronized void get()
{
if(!inFull)
{
try {
wait();
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.print(name);
System.out.println(":"+sex);
inFull=false;
notify(); }}
public class Producer implements Runnable {
Q q;
public Producer(Q q)
{
this.q=q;
}
public void run() {
int i=1;
while (true) {
if(i==1)
{
q.put("zhangsan", "boy");
}
else
{
q.put("wangwu", "girl");
}}}}
public class Consumer implements Runnable {
Q q;
public Consumer(Q q){
this.q=q;
}
public void run() {
// TODO Auto-generated method stub
while(true)
{
q.get(); } }}
public class ThreadConmunation {
public static void main(String[] args) {
Q q=new Q();
new Thread(new Producer(q)).start();
new Thread(new Consumer(q)).start();
}