试水JAVA多线程

为什么“多线程”的概念会出现

个人理解:

First,计算机各种部件运行的速度都不一样,但它是依赖整体协作而具有操作性。为了解决不同部件“速度”的协调问题,出现了“分时”,“多任务”切换的解决方案(同一时间通过快速切换执行多项任务),而这被称为多进程机制。
However,对于完全不相关的程序来说,在同时执行时,彼此的进程也不会做数据交换的工作,而可以完全独立地运行。但是对于同一程序所产生的多个“进程”,通常这种情况这多个进程构建时都会重复地复制相同的数据,因此如果同一程序的不同进程能够方便地“沟通”、相互协作就能提高工作效率。但现实是每个进程占有不同的内存空间,内存消耗很大,这使系统在不同的程序之间切换时开销很大,进程之间的通信速度很慢。
Finally,作为一种提高同一程序进程工作效率,同时减少不必要的系统负担的方法,线程就出现了。
运行一个进程时,程序内部的代码都是按顺序先后执行的。如果能够将一个进程划分为更小的运行单位,则程序中一些彼此独立的代码段就可以同时运行,从而获得更高的执行效率。线程就提供了这种同时执行的办法。由于同一进程的各个线程之间可以共享相同的内存空间,并利用这些共享内存来完成数据交换、实时通信及必要的同步工作,所以个线程之间的通信速度很快,线程之间进行切换所占用的系统资源也较少。

多线程在宏观上如何工作

这里写图片描述

值得注意的是“就绪状态”、“运行状态”与“阻塞状态”的切换

  • 就绪状态:就相当于在排队等着CPU叫号
  • 运行状态:自动执行本对象的run()方法,该方法定义了这一类线程的操作和功能。从该方法的第一条语句开始执行,一直到运行完毕,除非该线程主动让出CPU的控制权或者CPU的控制权被优先级更高的线程抢占。
  • 阻塞状态:一个正在执行的线程如果在某些特殊情况下,将让出CPU并暂时中止自己的执行,线程所处于这种不可运行的状态被称为阻塞状态。阻塞状态是因为某种原因,系统将不能执行线程的状态,在这种状态下即使CPU空闲也不能执行线程。

状态切换的情况

处于运行状态的线程在下列情况下将让出CPU的控制权进入阻塞状态

  • 线程运行完毕
  • 有比当前线程优先级更高的线程处于就绪状态
  • 线程主动睡眠一段时间
  • 线程在等待某一资源

阻塞条件被清除时才能再进入就绪状态

线程在代码层面的工作流程

Thread类的构造方法

  1. Thread()
  2. Thread(String name)
  3. Thread(Runable r)
  4. Thread(Runable r, String name)

Thread类常用方法

  • start();//启动线程
  • getId();//获得线程ID
  • getName();//获得线程名字
  • getPriority();//获得优先权
  • getPriority();//获得优先权
  • isAlive();//判断线程是否活动
  • isDaemon();//判断是否守护线程
  • getState();//获得线程状态
  • sleep(long mill);//休眠线程
  • join();//等待线程结束
  • yield();//放弃cpu使用权利
  • interrupt();//中断线程
  • currentThread();//获得正在执行的线程对象
由于Thread是类,无法解决多继承问题,于是出现了Runnable接口

Runnable接口API中的方法

void run()
使用实现接口 Runnable 的对象创建一个线程时,启动该线程将导致在独立执行的线程中调用对象的 run 方法。
方法 run 的常规协定是,它可能执行任何所需的动作。

使用方法:

class MyThread implements Runnable{run()}
MyThread you = new MyThread("你");
Thread t1 = new Thread(you);
t1.start();

由于Runnable接口里面只有一个抽象方法run(),需要Thread类去实现Runnable接口。但同时Thread中的run()方法也是“等着被覆盖”的,一般来说要定义一个子类覆盖Thread的run()。但现在有另一种机制可用:定义“类”实现Runnable接口,使用Thread的构造方法之一Thread(Runable r, String name)传入这个“类”,该构造方法的工作流程之一就是使用Runable r对象的run()方法。

线程间如何进行数据共享

操作同一个target对象,如

MyThread t = new MyThread(); //只创建一个实现Runnable接口的对象t
Thread t1 = new Thread(t,NO.1);
Thread t2 = new Thread(t,NO.2);
Thread t3 = new Thread(t,NO.3);
t1.start();
t2.start();
t3.start();

多线程如何实现同步控制

当一个线程对共享的数据进行操作时,应使之成为一个“原子操作”,即在没有完成相关操作之前,不允许其他线程打断它,否则,就会破坏数据的完整性。就是run(){原子操作},不允许别人在自己没干完活前瞎鸡儿打断自己的操作。
具体的方法是采用synchronized关键字来标识同步的资源。有下列几种格式

  • 同步语句。
Synchronized(对象)
{
    临界代码段
}
  • 同步方法
public synchronized 返回类型 方法名()
{
    方法体
}
等价于
public 返回类型 方法名()
{
    Synchronized(this)
    {
        方法体
    }
}

线程之间的通信

如果说线程的互斥是为了维持“自我界限不被别人侵犯”,那么线程的通信就相当于“与他人沟通合作”,类比到生活中,一个人如果只注重自我的感受而缺乏沟通能力,那么他的社会人格不会完整。
java.lang.Object类的wait()、notify()等方法为线程间的通信提供了有效手段

public final void wait() //释放自己的互斥锁给别的线程
public void notify() //唤醒正在等待该对象互斥锁的第一个线程
public void notifyAll()  //唤醒正在等待该对象互斥锁的所有线程,具有最高优先级的线程首先被唤醒并执行

NOTE:对于一个线程,若基于对象x调用wait()或notify()方法,该线程必须已经获得对象x的互斥锁。换句话说,wait()和notify()只能在同步代码块中使用

多线程设计后出现的问题以及相应的解决方法

无法多继承?

Runnable接口解决了该问题

如果想让多个线程有序执行,怎么办?

使用Thread的方法之一:join()。当某一线程调用join()方法时,则其他线程会等到该线程结束后才开始执行。注意:join()方法有可能出现InterruptedException,需要处理。

总结

多线程是提高工作效率的一种极好的机制,能有效避免cpu闲置,执行效率最大化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值