目录
相关内容:JAVA 基本知识 JAVA 类和对象 JAVA 类的特性 JAVA 文件读写
多线程
介绍什么是多线程,创建多线程的两种方法,
线程同步与互斥,后台线程。
进程与线程
- 程序是计算机指令的集合,而进程就是一个运行中的程序,它指的是从代码加载、执行到执行结束这样一个完整的过程。每个进程都是占用不同的内存空间
- 而线程(Thread)则是进程中某个单一顺序的控制流,也被称为轻量进程,它被操作系统调度,并在处理器或内核上运行。
- 一个进程都有一个主线程(primary thread),一个进程也可以由多个线程组成,每条线程并行执行不同的任务,这多个线程共享同一个内存空间。
(1)新建状态(new Thread)
Thread myThread = new MyThreadClass( );
- 当⼀个线程处于新建状态时,它仅仅是⼀个空的线 程对象,系统不为它分配资源
(2)就绪状态( Runnable )
myThread.start( );
- 当一个线程处于就绪状态时,系统为这个线程分配了它需的系统资源,安排其运行并调用线程运行方法,这样就使得该线程处于就绪( Runnable )状态。
- 需要注意的是这一状态并不是运行状态(Running ),因为线程也许实际上并未真正运行。由于很多计算机都是单处理器的,所以要在同一时刻运行所有的处于可运行状态的线程是不可能的,Java的运行系统必须实现调度来保证这些线程共享处理器
(3)运行状态(Running)
- 正在运行的线程处于运行状态,此时该线程独占CPU的控制权。如果有更高的优先级线程出现,则该线程将被迫放弃控制权进入可运行态。使用yield()方法可以使线程主动放弃CPU控制权。线程也可能由于执行结束或执行stop()方法放弃控制权进入终止状态。
(4)不可运行状态(non Runnable)
等待态、阻塞态、睡眠态
进入不可运行状态的原因有如下几条:
- 调用了sleep()方法;
-
如果线程调用sleep()方法进入了休眠状态,不能调用任何方法(interrupt)让它脱离阻塞状态,只能等待指定的时间之后,自动脱离阻塞态。
线程睡眠到期自动苏醒,并返回到可运行状态(就绪),不是运行状态。
-
- 调用了suspend()方法;
- 如果一个线程调用suspend()方法被挂起 而进入了阻塞状态,必须在其他线程中调用resume()方 法。
- 该线程正在等待I/O操作完成;
- 如果线程由于等待I/O而进入了阻塞状态,只能等待这个 I/O操作完成之后,系统调用特定的指令来使该线程恢复可 运行状态。
- 调用wait()方法;
- 如果线程为了等待一个条件变量而调用了wait()方法进入了 阻塞态,需要这个条件变量所在的那个对象调用notify(()或 notifyAll()方法。
- 输入输出流中发生线程阻塞。
(5)终止状态(Dead)
- 线程的终止一般可通过两种方法实现:自然撤消(线程执行完)或是被停止(调用stop()方法)。线程一旦进 入终止状态就不再存在了,也无法改变为其它状态。目 前不推荐通过调用stop()来终止线程的执行,而是让线程执行完。
(6)转换方法
创建多线程的两种方法
继承Thread类
class ThreadExample extends Thread{}
创建Thread对象:
ThreadExample1 t1 = new ThreadExample1 ();
this.getname();
特点:
- 不能再从其他类继承。
- 编写简单,可以直接操纵线程,*无需使用Thread.currentThread()*(用于获得Thread类对象)
实现Runable接口
class RunableExample implements Runnable{}
创建Thread对象:
RunableExample1 r = new RunableExample1();
Thread t = new Thread(r);
Thread.currentThread().getName()
特点:
-
可以将代码和数据分开,形成清晰的模型
-
还可以从其他类继承
-
保持程序风格的一致
-
共享一个目标对象,实现多个线程处理同一个资源
多线程共享资源例子
RunnableExample2 t1= new RunnableExample2();//创建线程类 Thread t1s = new Thread(t1); //创建线程 3个共享一个run(); Thread t2s = new Thread(t1); Thread t3s = new Thread(t1);
线程基本控制方法
都是Thread类的成员方法!首先要获得Thread类的某个对象。
-
public void start();//启动该线程,将导致run方法被自动调用。该方法将立即返回,新线程将运行
-
public void run();//必须覆盖该方法,在方法体中添加你想要在该线 程中执行的代码
-
public static void sleep(long millis) throws InterruptedException;//使当前正在执行的线程睡眠指定的时间
-
**public void interrupt()**;//用于将一个中断请求发送给线程
-
public static boolean interrupted();//用于测试当前线程(即正在执行该指令的线程)是否已经被中断
-
public boolean isInterrupted();//用于测试某个线程是否已经被中断
-
public final boolean isAlive();//用于测试某个线程是否还活着
-
public final void setPriority(int newPriority);//设置线程的优先级1-10 //不要假定高优先级的线程一定先于低优先级的线程执行,不要有逻辑依赖于线程优先级,否则可能产生意外结果
-
public final void join(long millis) throws InterruptedException;//使某个 线程等待指定的时间。调用某线程的该方法,将当前线程与该线程“ 合并”,即等待该线程结束,再恢复当前线程的运行。
-
public final int getPriority() ; //获得线程的优先级
-
public static Thread currentThread();返回代表当前正在执行的线程的 Thread对象
-
public static void yield() ;使当前正在执行的线程临时暂停,以使其它的线程运行
线程让步,不一定成功
-
public final void wait(long timeout) throws InterruptedException;当前线程被中断,并进入到一个对象的等待列表中,直到另外的线程调用同一个对象上的notify() 或notifyAll() 方法
-
public final void notify() ;用于将对象等待列表中的任选的一个线程唤醒,使它再次成为可运行的线程
-
public final void notifyAll();用于将对象等待列表中的所有线程唤醒, 使它们再次成为可运行的线程
- 线程睡眠sleep(int)
- 单位为ms
- 睡眠唤醒interrupt()
- 线程让步yield()
- 这种让步并不一定每次都见效,在调度机制的影响下也有可能没有成功让步 。
- 线程等待join()
- void join() 等待该线程终止。
- void join(long millis) 等待该线程终止的时间最长为 millis 毫秒。
- void join(long millis, int nanos) 等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒
线程互斥与同步
多线程同步
-
为了确保在任何时刻一个共享对象只被一个线程使用,必须使用“同步(synchronized)”
-
有两种方式实现同步:
synchronized void methodA() { } //使用同步块 synchronized(obj){ //obj是被锁定的对象 //要同步的语句 }
-
用synchronized来标识的块或方法即为监视器监视的部分。只有使用synchronized ,才能利用对象的监视器功能。
实现接口,共用一个类
public void run() {
while (true) {
synchronized (this) {
if (ticket > 0) {
try {//为了演示,线程在这里睡眠一次
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
} //睡眠结束后,继续当前的票进行销售
System.out.println(Thread.currentThread().getName() + "卖票-->" + (this.ticket--));
} else {
break;
}
}
}
}
继承Thread类的代码如何同步?
public void run() {
while(true){
synchronized("123"){
//函数体(要写break,判断退出)
if(ticket<0) break;
System.out.println(this.getName()+ "卖票-->"+(this.ticket--));
int ticketShell=ticket;
}
while(ticketShell==ticket){
"123".notify();
"123".waite();
}
sleep();
}
}