程序:
“程序(Program)”是一个静态的概念,一般对应于操作系统中的一个可执行文件,比如:我们要启动酷狗听音乐,则对应酷狗的可执行程序。当我们双击酷狗,则加载程序到内存中,开始执行该程序,于是产生了“进程”。
进程:
进程:正在进行的一个过程或者说一个任务。而负责执行任务则是cpu。
执行中的程序叫做进程(Process),是一个动态的概念。现代的操作系统都可以同时启动多个进程。比如:我们在用酷狗听音乐,也可以使用eclipse写代码,也可以同时用浏览器查看网页。进程具有如下特点:
1. 进程是程序的一次动态执行过程, 占用特定的地址空间。
2. 每个进程由3部分组成:cpu、data、code。每个进程都是独立的,且有自己的cpu时间,代码和数据,即便用同一份程序产生好几个进程,它们之间还是拥有自己的这3样东西,这样的缺点是:浪费内存,cpu的负担较重。
3. 多任务(Multitasking)操作系统将CPU时间动态地划分给每个进程,操作系统同时执行多个进程,每个进程独立运行。以进程的观点来看,它会以为自己独占CPU的使用权。
线程
一个进程可以产生多个线程。同多个进程可以共享操作系统的某些资源一样,同一进程的多个线程也可以共享此进程的某些资源(比如:代码、数据),所以线程又被称为轻量级进程(lightweight process)。
1. 一个进程内部的一个执行单元,它是程序中的一个单一的顺序控制流程。
2. 一个进程可拥有多个并行的(concurrent)线程。
3. 一个进程中的多个线程共享相同的内存单元/内存地址空间,可以访问相同的变量和对象,而且它们从同一堆中分配对象并进行通信、数据交换和同步操作。
4. 由于线程间的通信是在同一地址空间上进行的,所以不需要额外的通信机制,这就使得通信更简便而且信息传递的速度也更快。
5. 线程的启动、中断、消亡,消耗的资源非常少。
线程和进程的区别
1. 每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销。
2. 线程可以看成是轻量级的进程,属于同一进程的线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换的开销小。
3. 线程和进程最根本的区别在于:进程是资源分配的单位,线程是调度和执行的单位。
4. 多进程: 在操作系统中能同时运行多个任务(程序)。
5. 多线程: 在同一应用程序中有多个顺序流同时执行。
6. 线程是进程的一部分,所以线程有的时候被称为轻量级进程。
7. 一个没有线程的进程是可以被看作单线程的,如果一个进程内拥有多个线程,进程的执行过程不是一条线(线程)的,而是多条线(线程)共同完成的。
8. 系统在运行的时候会为每个进程分配不同的内存区域,但是不会为线程分配内存(线程所使用的资源是它所属的进程的资源),线程组只能共享资源。那就是说,除了CPU之外(线程在运行的时候要占用CPU资源),计算机内部的软硬件资源的分配与线程无关,线程只能共享它所属进程的资源。
java中实现多线程
通过继承Thread类实现多线程
继承Thread类实现多线程的步骤:
1. 在Java中负责实现线程功能的类是java.lang.Thread 类。
2. 可以通过创建 Thread的实例来创建新的线程。
3. 每个线程都是通过某个特定的Thread对象所对应的方法run( )来完成其操作的,方法run( )称为线程体。
4. 通过调用Thread类的start()方法来启动一个线程。
/**
*
* @author hecha
* 1. 继承Thread类,重写run()
* 2. 创建子类对象,start()启动
*/
public class StartThrad extends Thread{
/**
* 线程入口
*/
@Override
public void run() {
for(int i=0;i<20;i++){
System.out.println("一遍听歌");
}
}
//main主线程
public static void main(String[] args) {
//创建子类对象
StartThrad st = new StartThrad();
//启动线程
st.start(); // 不保证立即运行 cup调用
for(int i=0;i<100;i++){
System.out.println("一遍学习");
}
}
}
通过Runnable接口实现多线程
在开发中,我们应用更多的是通过Runnable接口实现多线程。这种方式克服了11.2.1节中实现线程类的缺点,即在实现Runnable接口的同时还可以继承某个类。所以实现Runnable接口的方式要通用一些,更方便共享资源。
package com.hcl.thread;
/**
*
* @author hecha
* 1. 实现Runnable,重写run()
* 2. 创建实现类对象+Thread对象+start()启动
* 3. run 方法不能throws 异常,不能有返回值
*
* 推荐:避免单继承的局限性,优先使用接口
* 方便共享资源
*
*/
public class StartRun implements Runnable{
/**
* 线程入口
*/
@Override
public void run() {
for(int i=0;i<20;i++){
System.out.println("一遍听歌");
}
}
//main主线程
public static void main(String[] args) {
//创建实现类对象
StartRun sr = new StartRun();
//创建代理类对象
Thread t= new Thread(sr);
//启动线程
t.start(); // 不保证立即运行 cup调用
//new Thread(new StartRun()).start();
for(int i=0;i<100;i++){
System.out.println("一遍学习");
}
}
}
举例:模拟抢票
package com.hcl.thread;
/**
* 共享资源
* @author hecha
*
*/
public class Web12306 implements Runnable{
private int tickets = 100;
@Override
public void run() {
// TODO Auto-generated method stub
while(tickets>0){
System.out.println(Thread.currentThread().getName()+"--->"+tickets--);
}
}
public static void main(String[] args) {
// 一个资源
Web12306 w = new Web12306();
//多个线程共享一个资源
new Thread(w,"AA").start();
new Thread(w,"BB").start();
new Thread(w,"CC").start();
}
}
/*
CC--->3
CC--->2
CC--->1
BB--->18
AA--->8*/
举例:龟兔赛跑
package com.hcl.thread;
/**
* 龟兔赛跑
* @author hecha
*
*/
public class Racer implements Runnable{
private String winner = null;
@Override
public void run() {
for(int step=1;step<=100;step++){
//让乌龟赢
if(Thread.currentThread().getName() == "兔子" && step%5==0 ){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"-->"+step++);
if(gameOver(step)){
break;
}
}
}
//判断游戏是否结束
private boolean gameOver(int step){
if(winner!=null){
return true;
}else{
if(step == 100){
winner = Thread.currentThread().getName();
System.out.println("winner==>"+winner);
return true;
}
}
return false;
}
public static void main(String[] args) {
Racer r = new Racer();
new Thread(r,"乌龟").start();
new Thread(r,"兔子").start();
}
}
/*
乌龟-->97
乌龟-->99
winner==>乌龟
兔子-->5
* */
通过实现Callable实现多线程(了解)
静态代理
Proxy
: 代理人——代替别人工作的人
“本人”寻找“代理人”工作,但是代理人毕竟是代理人,能代替本人所做的事有限,当代理人无法帮忙时再寻找本人
静态代理的实现模式:首先创建一个接口(JDK代理都是面向接口的),然后创建具体实现类(真实角色)来实现这个接口,再创建一个代理类同样实现这个接口,不同之处在于,具体实现类的方法中需要将接口中定义的方法的业务逻辑功能实现,而代理类中的方法只要调用具体类中的对应方法即可,这样我们在需要使用接口中的某个方法的功能时直接调用代理类的方法即可,将具体的实现类隐藏在底层。
/**
* 静态代理
* 接口:
* 1.真实角色
* 2.代理角色
* 真实角色和代理角色都实现接口,
* 在代理角色中传入真实角色对象,通过调用其方法实现静态代理
* @author hecha
*
*/
public class StaticProxy {
public static void main(String[] args) {
new WeddingCompany(new You()).happyMarry();
//new Thread(new XXX()).start();
}
}
//接口
interface Marry{
void happyMarry();
}
// 真实角色
class You implements Marry{
@Override
public void happyMarry() {
System.out.println("拜堂。。。 ");
}
}
//代理角色
class WeddingCompany implements Marry{
//真实角色
private Marry target;
public WeddingCompany(Marry target) {
this.target = target;
}
@Override
public void happyMarry() {
ready();
this.target.happyMarry();
after();
}
private void ready(){
System.out.println("闹洞房");
}
private void after(){
System.out.println("回家。。");
}
}